Harshit Mittal Harshit Mittal - 4 months ago 10
Java Question

handle NULL case inside sqlArgToJava of custom persister class

I'm using ormlite in one of my projects and I have a class

A
with a field
f
of custom type
F
and I have the requirement that field
f
should not be null in any case. So I want to instantiate a new object of class F whenever the field f is NULL in the database file

class A {
@DatabaseField(columnName = "xyz", persisterClass = FieldPersister.class)
F f;

public A() {
f = new F();
}
}


As per the docs I using a custom persister class
FieldPersister
and attempting a null check in there.

class FieldPersister extends StringType {
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
...
}

public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
if (sqlArg == null) return new F();
else {
String value = (String) sqlArg;
return new F(value);
}
}
}


I tried debugging the program and saw that there is already a null check in the following method

resultToJava(FieldType fieldType, DatabaseResults results, int columnPos)


Even overriding this method didn't resolved the issue which leads to my question, is there any way to handle this situation or am I missing some part of the puzzle?

Update with SSCCE:

pom.xml

Main.java

StringPropertyPersister.java

Answer

Even overriding this method didn't resolved the issue which leads to my question, is there any way to handle this situation or am I missing some part of the puzzle?

You are missing a part of the puzzle and it's pretty subtle. Unfortunately the the ResultSet.getInt(...) method returns an int. Why does this matter? Because ORMLite can't tell if the field in the database is NULL or not if it is a primitive. So typically what happens is that ORMLite gets a result from the ResultSet, asks it to be converted by the custom converter, and then ORMLite sees if it is null and adjusts the value appropriately. Maybe there are better ways to do that. I'll need to think about it.

You have a couple of solutions here.

  1. Add a defaultValue = "" to the definition of your field. This won't handle the case if there is NULL value on disk but it will work if you are using dao.create(...). You then can use FieldConverter.parseDefaultString(...) to define your default object to insert if the field is null.

  2. In your A.getValue() method, you do the null check there and return a new SimpleStringProperty("") if it is null. But then your example code maybe be overly simplistic.

  3. The hack is to override both the resultToJava(...) method to be something like:

    @Override
    public Object resultToJava(FieldType fieldType, DatabaseResults results,
            int columnPos) throws SQLException {
        // remove the null check here so we can handle the null
        Object value = resultToSqlArg(fieldType, results, columnPos);
        return sqlArgToJava(fieldType, value, columnPos);
    }
    

    But you also need to override the following which is a hack.

    @Override
    public boolean isStreamType() {
        // this forces the null check to be ignored
        return true;
    }
    

    This is a hack because if ORMLite subtly changes the way it handles "stream" SQL types, it might break your code.

    See my version of your test here: CustomFieldNullTest.java.

Comments