如何将对象强制转换为JsType?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将对象强制转换为JsType?相关的知识,希望对你有一定的参考价值。
我已声明以下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返回一个具有相同属性的新对象(它们遵循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);
}
当我的FeatureCollection成为本机JsType时,它可以工作,但阻止我使用我当前的构造函数,所以我正在寻找一种方法将javascript对象强制转换为我的JsType。
@JsType
和相关的注释不会创建包装器来试图理解你的意图,但它们实际上生成的JS代码尽可能地与你所做的相对应。这意味着如果你说“我正在创建一个新的非本机JS类型,它将有一个像这样定义的构造函数”,GWT会说“好”并且这样做。结果将是带有构造函数的JS中的类型,但是根据定义不是使用该精确构造函数创建的对象不属于该类型,如果您尝试将它们视为它们,则可能会出现错误。
相反,你的FeatureCollection
几乎肯定是一个本机类型,可能是Object
命名空间中的简单JsPackage.GLOBAL
,而不是构造函数,你应该有一个工厂方法。
或者,您可能冒险使用Js.uncheckedCast
说“相信我,这个对象或多或少是正确的形状(虽然它可能是错误的类型),只需使用它就像它是相同的类型”,只要GWT有没有理由进一步检查,它会让你逃脱它。这可能适用于您自己的应用程序代码,但有关于您正在做什么以及何时出错的非常明确的说明。
旁注 - 通常如果你有一个非本地JsType
的getter和setter,你应该将它们标记为@JsProperty
而不是标记私有字段 - 如果你让字段最终,其他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);
}
}
基于this one的示例,其中还包括jackson注释,因此它也可以在服务器端。
以上是关于如何将对象强制转换为JsType?的主要内容,如果未能解决你的问题,请参考以下文章
无法将整数强制转换为android.support.design.widget.FloatingActionButton
java中可以将父类对象强制转换为子类对象吗?直接将父类对象强制转换为子类对象,与将上转型对象强制
无法将类型为“System.Windows.Forms.SplitContainer”的对象强制转换为类型“System.ComponentModel.ISupportInitialize”