Java 如何将对象强制转换为JsType?
为了操作兼容数据,我声明了以下JsType:Java 如何将对象强制转换为JsType?,java,gwt,gwt-jsinterop,Java,Gwt,Gwt Jsinterop,为了操作兼容数据,我声明了以下JsType: @JsType public class FeatureCollection extends GeoJson { @JsProperty private Feature[] features; public FeatureCollection() { super("FeatureCollection"); features = new Feature[]{}; } publ
@JsType
public class FeatureCollection extends GeoJson {
@JsProperty
private Feature[] features;
public FeatureCollection() {
super("FeatureCollection");
features = new Feature[]{};
}
public Feature[] getFeatures() {
return features;
}
有时,我需要将我的FeatureCollection
对象传递给外部库(例如Turps.js以执行单位转换),外部库通过功能访问数据。lib返回给我一个具有相同属性的新对象(它们遵循GeoJson RFC,就像我的JsType一样),但我无法将其转换回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);
}
@JsType(isNative=true,namespace=GLOBAL,name=“turp”)
公营草皮{
公共静态本机T-toWgs84(T-geojson);
}
当我将FeatureCollection设置为本机JsType时,它可以工作,但会阻止我使用当前的构造函数,因此我正在寻找一种将javascript对象回溯到我的JsType的方法。@JsType
和相关注释不会创建试图理解您的意图的包装器,但它们实际上生成的JS代码与您所做的尽可能接近。这意味着,如果您说“我正在创建一个新的非本地JS类型,它将有一个这样定义的构造函数”,GWT将说“好”,然后执行它。结果是JS中有一个构造函数的类型,但根据定义,没有使用该构造函数创建的对象不属于该类型,如果您试图将其视为构造函数,则可能会出错
相反,您的FeatureCollection
几乎肯定应该是JsPackage.GLOBAL
命名空间中的原生类型,可能是普通的Object
,并且应该有一个工厂方法,而不是构造函数
或者,您可以冒险使用Js.uncheckedCast
说“相信我,这个对象的形状或多或少是正确的(尽管它可能是错误的类型),只要像使用相同的类型一样使用它”,只要GWT没有理由进一步进行类型检查,它就会让您侥幸逃脱。这可能适合在您自己的应用程序代码中使用,但要非常清楚地说明您正在做什么以及何时会出错
旁注-通常,如果在非本机JsType
中有getter和setter,则应将其标记为@JsProperty
,而不是标记私有字段,因此-如果将字段设置为final,其他JS可能会在稍后分配它,如果您让getter或setter执行一些验证或缓存,任何来自JS的访问都会错过这一点。还请记住,如果一个类型是JsType
,它将自动导出其所有公共成员,因此您可以通过删除JsProperty
和getter来实现同样的效果,@JsType
和相关注释不会创建试图理解您的意图的包装,但它们实际上生成的JS代码与您所做的尽可能接近。这意味着,如果您说“我正在创建一个新的非本地JS类型,它将有一个这样定义的构造函数”,GWT将说“好”,然后执行它。结果是JS中有一个构造函数的类型,但根据定义,没有使用该构造函数创建的对象不属于该类型,如果您试图将其视为构造函数,则可能会出错
相反,您的FeatureCollection
几乎肯定应该是JsPackage.GLOBAL
命名空间中的原生类型,可能是普通的Object
,并且应该有一个工厂方法,而不是构造函数
或者,您可以冒险使用Js.uncheckedCast
说“相信我,这个对象的形状或多或少是正确的(尽管它可能是错误的类型),只要像使用相同的类型一样使用它”,只要GWT没有理由进一步进行类型检查,它就会让您侥幸逃脱。这可能适合在您自己的应用程序代码中使用,但要非常清楚地说明您正在做什么以及何时会出错
旁注-通常,如果在非本机JsType
中有getter和setter,则应将其标记为@JsProperty
,而不是标记私有字段,因此-如果将字段设置为final,其他JS可能会在稍后分配它,如果您让getter或setter执行一些验证或缓存,任何来自JS的访问都会错过这一点。还请记住,如果一个类型是JsType
,它将自动导出其所有公共成员,因此您可以通过删除JsProperty
和getter来实现同样的效果,并将字段公开。正如科林所解释的,您没有任何类型可以签入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);
}
}
导入静态jsinterop.annotations.JsPackage.GLOBAL;
导入javax.annotation.Nullable;
导入jsinterop.annotations.JsOverlay;
导入jsinterop.annotations.JsType;
@JsType(namespace=GLOBAL,name=“Object”,isNative=true)
类GeoJson{
公共字符串类型;
public final@JsOverlay Type getTypeEnum(){return Type.valueOf(Type);}
public final@JsOverlay void setTypeEnum(Type){this.Type=Type.name();}
公共静态@JsOverlay FeatureCollection FeatureCollection(功能…功能){
FeatureCollection o=新FeatureCollection();
o、 setTypeEnum(Type.FeatureCollection);
o、 特征=特征;
返回o;
}
public static@JsOverlay特征(几何体){返回特征(null,几何体);}
公共静态@JsOverlay功能(@Nullable String featureId,Geometry){
特征o