我已声明以下JsType以便处理GeoJson兼容数据:
@JsType
public class FeatureCollection extends GeoJson {
@JsProperty
private Feature[] features;
public FeatureCollection() {
super("FeatureCollection");
features = new Feature[]{};
}
public Feature[] getFeatures() {
return features;
}
有时,我需要将FeatureCollection
对象传递给外部库(例如,通过Turfs.js执行单位转换),该外部库通过features
属性访问数据。 lib向我返回了一个具有相同属性的新对象(它们遵循我的JsType一样遵循GeoJson RFC),但是我无法将其强制转换回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
Turf库是JsInteroped:
@JsType(isNative = true, namespace = GLOBAL, name = "turf")
public class TurfUtils {
public static native <T extends GeoJson> T toWgs84(T geojson);
}
将FeatureCollection设为本机JsType时,它可以工作,但会阻止我使用当前的构造函数,因此,我正在寻找一种将javascript对象回退到JsType的方法。
答案 0 :(得分:2)
@JsType
和相关注释不会创建试图理解您 meant 要做什么的包装器,但是它们实际上会生成与您尽可能近地对应的JS代码。 >做到。这意味着如果您说“我正在制作一个新的非本地JS类型,并且它将具有这样定义的构造函数”,则GWT将说“好”并执行该操作。结果将是JS中具有构造函数的类型,但是未按定义使用该确切构造函数创建的对象却不是该类型的对象,并且如果尝试将它们视为真实对象,则可能会出错。
相反,您的FeatureCollection
几乎应该是本机类型,可能在Object
命名空间中是纯JsPackage.GLOBAL
,并且应该有一个factory方法来代替构造函数。>
或者,您可能会冒用Js.uncheckedCast
说“相信我,这个对象或多或少是正确的形状(尽管它可能是错误的类型),就像使用相同的类型一样使用它” ,并且只要GWT没有理由进一步进行类型检查,它就会让您摆脱它。这可能适合在您自己的应用程序代码中使用,但要非常清楚地说明您在做什么以及何时会出错。
旁注-通常,如果在非本机JsType
中有getter和setter,则应将它们标记为@JsProperty
而不是标记私有字段,因此-如果将字段定为final,则其他无论如何,JS可能会在以后分配它,如果您使getter或setter进行一些验证或缓存,那么从JS进行的任何访问都将丢失它。还要记住,如果类型是JsType
,它将自动导出其所有公共成员,因此您可以通过删除JsProperty
和getter,并使该字段成为公共字段来实现相同的目的。
答案 1 :(得分:1)
正如Colin解释的那样,您没有任何类型可以签入GeoJson
对象,因此您不能使用instanceof
或其他OOP技术将其强制转换回特定的类型安全性。您必须将类型设置为native=true, name="Object", namespace=GLOBAL
,然后才能使用Js.cast
将其回退为GeoJson
类型。
如果您想要更多OOP,则可以使用访问者模式,并将“手动类型检查”隐藏在该访问者后面,例如:
import static jsinterop.annotations.JsPackage.GLOBAL;
import javax.annotation.Nullable;
import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsType;
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
class GeoJson {
public String type;
public final @JsOverlay Type getTypeEnum() { return Type.valueOf(type); }
public final @JsOverlay void setTypeEnum(Type type) { this.type = type.name(); }
public static @JsOverlay FeatureCollection featureCollection(Feature... features) {
FeatureCollection o = new FeatureCollection();
o.setTypeEnum(Type.FeatureCollection);
o.features = features;
return o;
}
public static @JsOverlay Feature feature(Geometry geometry) { return feature(null, geometry); }
public static @JsOverlay Feature feature(@Nullable String featureId, Geometry geometry) {
Feature o = new Feature();
o.setTypeEnum(Type.Feature);
o.id = featureId;
o.geometry = geometry;
return o;
}
public static @JsOverlay Point point(double x, double y) { return point(new double[] { x, y }); }
public static @JsOverlay Point point(double[] coordinates) {
Point o = new Point();
o.setTypeEnum(Geometry.Type.Point);
o.coordinates = coordinates;
return o;
}
public static @JsOverlay Polygon polygon(double[][] coordinates) {
Polygon o = new Polygon();
o.setTypeEnum(Geometry.Type.Polygon);
o.coordinates = new double[][][] { coordinates };
return o;
}
public enum Type {Feature, FeatureCollection}
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
public static final class Feature extends GeoJson {
public @Nullable String id;
public Geometry geometry;
}
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
public static class FeatureCollection extends GeoJson {
public Feature[] features;
}
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
public static abstract class Geometry {
public String type;
public final @JsOverlay Geometry.Type getTypeEnum() { return Geometry.Type.valueOf(type); }
public final @JsOverlay void setTypeEnum(Geometry.Type type) { this.type = type.name(); }
public final @JsOverlay <T> T accept(GeometryVisitor<T> fn) { switch (getTypeEnum()) {
case Point: return fn.point((Point) this);
case Polygon: return fn.polygon((Polygon) this);
default: throw new UnsupportedOperationException("unexpected type " + type);
} }
public static @JsOverlay @Nullable Point isPoint(@Nullable Geometry g) {
return g == null ? null : g.accept(new GeometryVisitor<Point>() {
@Override public Point point(Point g) { return g; }
@Override public Point polygon(Polygon p) { return null; }
});
}
public static @JsOverlay @Nullable Polygon isPolygon(@Nullable Geometry g) {
return g == null ? null : g.accept(new GeometryVisitor<Polygon>() {
@Override public Polygon point(Point g) { return null; }
@Override public Polygon polygon(Polygon p) { return p; }
});
}
public enum Type {Point, Polygon}
}
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
public static class Point extends Geometry {
public double[] coordinates;
public final @JsOverlay double x() { return coordinates[0]; }
public final @JsOverlay double y() { return coordinates[1]; }
}
@JsType(namespace = GLOBAL, name = "Object", isNative = true)
public static final class Polygon extends Geometry {
public double[][][] coordinates;
public final @JsOverlay double[][] shell() { return coordinates[0]; }
}
public interface GeometryVisitor<T> {
T point(Point g);
T polygon(Polygon p);
}
}
基于this one的示例,其中还包括杰克逊注释,因此它也可以在服务器端。