yahoo / squidb

SquiDB is a SQLite database library for Android and iOS
https://github.com/yahoo/squidb/wiki
Apache License 2.0
1.31k stars 132 forks source link

java.lang.UnsupportedOperationException: numbers not found in model. Make sure the value was set explicitly, read from a cursor, or that the model has a default value for this property. #256

Closed lpellegr closed 7 years ago

lpellegr commented 7 years ago

I am using Squidb with the JSON plugin.

Below is my use case example:

@TableModelSpec(className = "AlertContact", tableName = "AlertContact", noRowIdAlias = true)
public class AlertContactSpec {

    public long createdAt;

    // ...

    @JSONColumn
    public List<String> numbers;

    @ModelMethod
    public static void addNumber(AlertContact alertContact, String number) {
        List<String> numbers = alertContact.getNumbers();

        if (numbers == null) {
            alertContact.setNumbers(Lists.newArrayList(number));
        } else {
            if (!numbers.contains(number)) {
                numbers.add(number);
                alertContact.setNumbers(numbers);
            }
        }
    }

}

I have recently upgraded to Squidb 3.2.3 from 3.2.2. Since this update, I am getting the following error:

java.lang.UnsupportedOperationException: numbers not found in model. Make sure the value was set explicitly, read from a cursor, or that the model has a default value for this property.

when I try to execute:

Database database = Database.getInstance(mContext);

database.beginTransaction();

try {
    AlertContact alertContact = database.fetchByQuery(
            AlertContact.class,
            Query.select(AlertContact.PROPERTIES)
                    .where(AlertContact.CONTACT_ID.eq(mContactId)));

    if (alertContact == null) {
        alertContact = new AlertContact();
        alertContact.setCreatedAt(System.currentTimeMillis());
        alertContact.setContactId(mContactId);
        alertContact.setName(mDisplayName);
    }

    alertContact.addNumber(mNumber);

    database.persist(alertContact);

    database.setTransactionSuccessful();

    return true;
} catch (Exception e) {
    FirebaseCrash.report(e);
    return false;
} finally {
    database.endTransaction();
}

The exception is thrown when alertContact.addNumber(mNumber); is executed.

A quick debugging lets me think the issue is due to the fact that the field numbers from AlertContactSpec has no default value. However, I have no idea how to set a default value for this JSON field. Is it possible? if yes, what about backward compatibility with schema created without this default value?

https://github.com/yahoo/squidb/blob/master/squidb/src/com/yahoo/squidb/data/AbstractModel.java#L323

sbosley commented 7 years ago

@lpellegr yes, this is actually a bug fix in 3.2.3 to make JSONProperties behave the same as other properties when the field is not present in the model. If you want a default value of null to be present in the in-memory values, simply specify it using @ColumnSpec:

@ColumnSpec(defaultValue=ColumnSpec.DEFAULT_NULL)
List<String> numbers;

The SQLite column will default to null anyways, so no migration is necessary, but you need to explicitly specify if you want an in-memory default value for unpersisted models or models that didn't read all properties from the database. This is also consistent with how all other property types behave.

Hope that helps!

lpellegr commented 7 years ago

@sbosley Thank you for the clear explanations. Problem fixed.