I'm struggling with JSNI method return types to ensure that one of my DTO object can really have nullable properties. This was the very first and obviously unsuccessful try for the overlay DTO:
public class Dto extends JavaScriptObject {
protected Dto() {
}
private native Integer getValue1() /*-{ return this.value1; }-*/;
// no longs are allowed
private native Double getValue2() /*-{ return this.value2; }-*/;
// TODO migrate to Java 8
public static final Function<Dto, DomainObject> dtoToDomainObject = new Function<Dto, DomainObject>() {
@Override
public DomainObject apply(Dto dto) {
return new DomainObject(
dto.getValue1(),
(long) dto.getValue2()
);
}
};
}
As per the documentation, the outgoing types are just String
, boolean
, Java numeric primitive (with certain restrictions), JavaScriptObject
, Object
, and arrays. And this restriction does not seem to fit the nullable semantics, because of various runtime exceptions that prevent passing JavaScript "primitive" via a Number
box or vice versa. This is somewhat strange, but I believe there were solid technical arguments for it. Anyway. So far after getting a lot of exceptions during my experiments, I've gained the following way:
public class Dto extends JavaScriptObject {
protected Dto() {
}
private native boolean hasValue1() /*-{ return typeof(this.value1) != "undefined" && this.value1 != null; }-*/;
private native int getValue1() /*-{ return this.value1; }-*/;
private native boolean hasValue2() /*-{ return typeof(this.value2) != "undefined" && this.value2 != null; }-*/;
// no longs are allowed
private native double getValue2() /*-{ return this.value2; }-*/;
// TODO migrate to Java 8
public static final Function<Dto, DomainObject> dtoToDomainObject = new Function<Dto, DomainObject>() {
@Override
public DomainObject apply(Dto dto) {
return new DomainObject(
dto.hasValue1() ? dto.getValue1() : null,
dto.hasValue2() ? (long) dto.getValue2() : null
);
}
};
}
The second implementation finally works as I expect letting me distinguish between real values and nulls. But this is a very huge boilerplate with at least the following disadvantages:
has
-methods;I'm wondering: how can I use/implement complete nullable semantics for JSNI methods in a more elegant way without that huge boilerplate?
You won't cut down much boilerplate (though you could have simplified your code above). The code would look like:
private native Integer getValue1() /*-{
return this.value1 == null ? null : @java.lang.Integer::valueOf(I)(this.value1);
}-*/;
private native Long getValue2() /*-{
return this.value2 == null ? null : @my.app.client.Dto::doubleToLong(D)(this.value2);
}-*/;
private static Long doubleToLong(double d) {
return Long.valueOf((long) d);
}
BTW, your double-to-long code in the first snippet is wrong, it would throw an NPE if the value is null
. You'd have to check for nulls before casting to long (or getting longValue()
)