简体   繁体   中英

How to set a default value for a @JsProperty?

I'm building a Jsinteropted wrapper for Mapbox-gl-js 's source objects.

I've an abstract class Source which embed default methods like getting/setting the type of the source.

@JsType(isNative = true, namespace = GLOBAL, name = JS_OBJECT_NAME)
public class Source {

    @JsProperty
    protected final native String getType();

    @JsProperty
    protected final native void setType(String type);

}

And I've some inherited class which must (according to Mapbbox documentation) define the type property! So I would like to do something like:

@JsType(isNative = true, namespace = GLOBAL, name = JS_OBJECT_NAME)
public class GeoJsonSource extends Source {

    @JsConstructor
    public GeoJson() {
        setType("geojson");
    }

}

or

@JsType(isNative = true, namespace = GLOBAL, name = JS_OBJECT_NAME)
public class GeoJsonSource extends Source {

    @JsProperty
    private String type = "geojson";

}

But both are forbidden by GWT compiler.

For now I use a factory which create the GeoJsonSource and then put the right type property, but I wonder if there is a Jsinteropt way to do it?

How do you set a default value on someone else's type? You don't.

Remember, you've told the compiler that you are just describing the js class Object - if there are defaults, they already exist.

Consider how you would do this in JS - usually this would just be {type:"geojson"} or var obj = {}; obj.type = "geojson"; var obj = {}; obj.type = "geojson"; to do your two required steps of a) creating a plain Object, and b) assigning some type which must be there by default.

A factory would work, perhaps a static method in GeoJsonSource so it is clear what you are making.


The other option is to not mark the GeoJsonSource type as native , and not give it a name of Object in the global namespace (ie you aren't allowed to rewrite someone else's data), if that is appropriate for your use case. This would now allow you to control the class - defining default values, adding logic in constructors and such, but you must make sure that the methods are exported correctly.

Limitations of this approach include the fact that any object read from a JSON string will not be your GeoJsonSource type (but on the other hand, that may not matter, since it probably already has the type property. Logic would still be missing from its methods though, since reading from JSON always creates plain Object instances (unless you pass a reviver function to JSON.parse() ).

Similarly, a plain Object passed from JS or read from JSON.parse() will not correctly pass an instanceof check against your non-native type, which may require you to use Js.uncheckedCast in some places where you would normally write idiomatic Java.


Since you are building a wrapper (likely to be used by others, who may not necessarily understand those limitations as completely as you), I'd tend to favor the factory approach - yes, it requires a little more setup on your side, but it is clearer in plain JS what you are asking for, and will behave more predictably if someone treats a plain JS Object as a Java GeoJsonSource (because it is one).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM