I've declare the following JsType in order to manipulate [GeoJson][1] compliant data :
@JsType
public class FeatureCollection extends GeoJson {
@JsProperty
private Feature[] features;
public FeatureCollection() {
super("FeatureCollection");
features = new Feature[]{};
}
public Feature[] getFeatures() {
return features;
}
Sometimes I need to pass my FeatureCollection object to external libraries (like Turfs.js for instance to perform unit conversion) which access data throught features properties. The lib returns me a new object with same properties (they follow the GeoJson RFC like my JsType) but I can't cast it back to FeatureCollection:
FeatureCollection fc = new FeatureCollection();
Object o = TurfUtils.toWgs84(fc); // Works and give an object which respect the FeatureCollection scheme (ie an array of Features) when I print it on the javascript console.
FeatureCollection featureCollection = TurfUtils.toWgs84(fc); // Throw a java.lang.ClassCastException
The Turf library is JsInteroped:
@JsType(isNative = true, namespace = GLOBAL, name = "turf")
public class TurfUtils {
public static native <T extends GeoJson> T toWgs84(T geojson);
}
When making my FeatureCollection a native JsType, it works but prevent me to use my current constructor, so I'm looking for a way to cast back a javascript object to my JsType. [1]: https://www.rfc-editor.org/rfc/rfc7946
The
@JsTypeand related annotations do not create wrappers that try to understand what you meant to do, but they actually generate JS code that corresponds as closely as possible to what you did do. This means that if you say "I'm making a new non-native JS type, and it will have a constructor defined like this", GWT will say "okay" and do it. And the result will be a type in JS with a constructor, but objects not created with that exact constructor by definition, are not of that type, and you may get an error if you try to treat them as if they were.Instead, your
FeatureCollectionshould almost certainly be a native type, probably plainObjectin theJsPackage.GLOBALnamespace, and instead of a constructor, you should have a factory method.Alternatively, you could risk using
Js.uncheckedCastto say "trust me, this object is more or less the right shape (though it might be the wrong type), just use it as if it were the same type", and as long as GWT has no reason to typecheck further, it will let you get away with it. This is probably suitable for use in your own application code, but with very clear notes about what you are doing and when it will go wrong.Side note - generally if you have getters and setters in a non-native
JsType, you should mark them as@JsPropertyinstead of marking the private field so - if you made the field final, other JS might assign it later anyway, if you made the getter or setter do some validation or caching, any access from JS would miss that. Remember too that if a type is aJsTypeit will automatically have all of its public members exported, so you could achieve the same thing here by just removingJsPropertyand the getter, and make the field public.