我在应用程序中使用了RoboGuice和Gson
在某些情况下,我需要gson将json注入到接口中,但是Gson不知道如何注入接口,除非您提供一个实例创建器,该实例创建器在实现类与其接口之间进行映射。
与roboguice相同的方式,它也需要完全相同的映射。
为了测试我的应用程序,我想给roboguice和gson提供相同的实现映射。
如何获取roboguice绑定的接口实现,以便将它们传递给GsonBuilder InstanceCreator?
发布于 2014-01-23 18:44:04
Roboguice (好吧,Guice)实际上能够“注入到界面中”,这就是它设计的目的。假设您有以下代码:
public class ExampleClass {
@Inject InterfaceType mExampleField;
...当您注入一个ExampleClass实例时,Guice将会影响您在注入配置中绑定到InterfaceType的InterfaceType的具体子类型。假设您初始化注入器的模块如下所示:
public class ExampleModule extends AbstractModule {
@Override
protected void configure() {
bind(InterfaceType.class).to(ConcreteType.class);
}
}提供了以下定义:
public interface InterfaceType { }
public class ConcreteType implements InterfaceType { ... }如果你现在在某个地方注入一个ExampleClass,例如
@Inject ExampleClass mExample;然后mExample.mExampleField将引用一个ConcreteType对象。
现在,我的理解是,您想要做的是为Guice模块绑定到InterfaceType的具体类构建一个实体。你可以这样做:
public class ExampleClass {
@Inject InterfaceType mDummyExampleField;
private final Gson mGson = ...;
...
public InterfaceType buildBoundSubTypeFromJson(final String json) {
return mGson.fromJson(json, mDummyExampleField.getClass());
}
}Guice将动态查找mExampleField引用的实例的具体类型,以创建此类型的对象。mExampleField由注入器填充,因此它将是您将InterfaceType接口绑定到的具体类型。
这意味着在上面的示例中,buildBoundSubTypeFromJson()将返回实际类型为ConcreteType的对象。
或者,稍微干净一点:
public class Deserializer {
private final Class<? extends InterfaceType> mConcreteType;
@Inject
public Deserializer(final InterfaceType dummy) {
mConcreteType = dummy.getClass();
}
private final Gson mGson = ...;
...
public InterfaceType buildBoundSubTypeFromJson(final String json) {
return mGson.fromJson(json, mConcreteType);
}
}这是可行的,但我认为这将是非常危险的,因为Json字符串必须与您绑定接口的实际类型相匹配,这取决于您当前的注入设置,或者接口的所有子类型都必须与通用的json格式匹配,这两种格式都不能静态强制执行。
另一个稍强一点的解决方案是让Json数据反序列化为唯一的实体类型(假设Json数据总是相同的情况),然后通过一个转换器对象将其转换为InterfaceType,该转换器对象可以被注入(并绑定到与InterfaceType绑定的类型相匹配的子类型之一)。
还请注意,您可以通过访问Guice的配置来动态地从Guice检索类型,如下所示:
injector
.getBinding(InterfaceType.class)
.acceptTargetVisitor(new DefaultBindingTargetVisitor<InterfaceType, InterfaceType>() {
@Override
public InterfaceType visit(LinkedKeyBinding<? extends InterfaceType> binding) {
mConcreteType = binding.getLinkedKey().getTypeLiteral());
return visitOther(binding);
}
// don't forget to override other visit methods if you except other types of bindings !
});如果你想让它不那么老土的话。
因此,看起来您正在尝试反序列化一个类型,该类型声明了一个接口类型的字段,如下所示:
ExampleClass example = mGson.fromJson(json, ExampleClass.class);这里的example.mExampleField是空的。这是正常的,因为Gson无法知道您希望为mExampleField实例化哪个对象。
这个问题的解决方案是使用custom deserialization,这意味着您可以控制Gson对该类型的反序列化过程。
结合第一个关于从注入设置中获取具体类型的问题,这应该看起来有点像:
class ExampleDeserializer implements JsonDeserializer<InterfaceType>() {
private final Class<? extends InterfaceType> mConcreteType;
@Inject
public ExampleDeserializer(final InterfaceType dummy) {
mConcreteType = dummy.getClass();
}
@Override
public InterfaceType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return context.deserialize(json, mConcreteType);
}}
别忘了在创建Gson实例的地方注册这个自定义的反序列化程序:
public class AnotherClass {
private final Gson mGson;
@Inject
public AnotherClass(ExampleDeserializer mExampleDeserializer) {
mGson = new GsonBuilder().registerTypeAdapter(InterfaceType.class, mExampleDeserializer).create();
// now you can deserialize ExampleClass Json representation using mGson
}
}https://stackoverflow.com/questions/21294185
复制相似问题