在Gson反序列化过程中使用Dagger进行依赖注入

时间:2018-09-02 08:33:00

标签: java dependency-injection gson dagger

在我的应用程序中,我不是由我而是由Gson反序列化器创建的对象。这些对象需要引用单例实例,我可以使用构造函数注入在其他地方提供这些实例。

但是,像这样通过Gson调用的默认构造函数访问相关组件

5            #length of the array
1 2 3 4 5     #inputs separated by space

不会重用注入到其他地方的单例-从我的理解中,这是因为构建器实际上将创建DaggerExampleComponent.builder().build().inject(this) 的新实例,而该实例对现有实例一无所知。

我的解决方法是在ExampleComponent内保留一个静态instance字段以及一个吸气剂,但是我想知道是否存在使用另一种方法实现同一目标的最佳实践。

编辑:正在对使用Android Room Persistence library从数据库中检索到的数据进行反序列化。通过在静态方法上使用ExampleComponent批注来实现将数据转换为自定义对象的方法,当从数据库中检索元素时会隐式调用该批注。这阻止了我将创建的对象注入到那里-转换器是未实例化的静态类中的静态方法,因此我无法将DaggerComponent对象传递给它以用于注入创建的实例,如下面的Thorben建议的那样。 / p>

1 个答案:

答案 0 :(得分:0)

免责声明

我很久没有和Dagger合作了。盐以下采取解决方案!该解决方案在本地对我有效。

没有DaggerExampleComponent

问题的一个答案可能是,使用自定义的JsonDeserializer接口实现,该接口实现将要注入的对象的实例作为构造函数参数。

您可以编写自己的反序列化器,将单例实例注入反序列化的对象中,如下所示:

class MyJsonDeserializer implements JsonDeserializer<MyObject> {

    private final MyComponent singleton;

    public MyJsonDeserializer(MyComponent component) {
        this.singleton = component;
    }

    public MyObject deserialize(JsonElement json, Type tye, JsonDeserializationContext context) throws JsonParseException {
        // you could here parse some arguments
        return new MyObject(singleton);
    }
}

您可以这样注册它:

MyComponent component = ...
Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyJsonDeserializer(component)).create();

如果要注入MyComponent类,则可以确保每个创建的对象都具有MyComponent对象的相同实例。

我个人希望此解决方案不要混淆Dagger和Gson。

使用匕首

您还可以像这样在JsonDeserializer中更改代码以使用DaggerAppComponent:

class MyJsonDeserializer implements JsonDeserializer<MyObject> {

    private final DaggerAppComponent singletonProvider;

    public MyJsonDeserializer(DaggerAppComponent componentProvdider) {
        this.singletonProvider = componentProvider;
    }

    public MyObject deserialize(JsonElement json, Type tye, JsonDeserializationContext context) throws JsonParseException {
        // you could here parse some arguments
        MyObject object =  ...
        singletonProvider.inject(object);
        return object;
    }
}

并像这样更改注册:

DaggerAppComponent componentBuilder = DaggerExampleComponent.builder().build();
Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyJsonDeserializer(componentBuilder)).create();

更新

由于有了新信息,我建议增强现有类,该类用于Android Room Persistence库(包含带注释方法的类),如下所示:

class Convert {
    static DaggerAppComponent singletonProvider;
    @TypeConverter
    public static MyObject convert(String arg) {
        Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyJsonDeserializer(componentBuilder)).create();
        return gson.fromJson(arg, MyObject.class);
    }

    @TypeConverter
    public static String fromArrayLisr(MyObject object) {
        Gson gson = new Gson();
        String json = gson.toJson(v);
        return json;
    }
}

我从thetechguru得到了一些启发。而且,这假定了与上述相同的JsonDeserializer。

由于我不知道实际参数,因此我将String假定为此typeconverter的参数。在其中插入相应的类型。

要有效地使用此代码,请在代码中的某个位置(在完成任何与数据库相关的工作之前),应将其称为:

Convert.singletonProvider = DaggerExampleComponent.builder().build();

这将允许Convert类查看正确的DaggerAppComponent。

这可能仍然有问题。这是race condition,属于静态变量的null状态。如果很快调用数据库,结果将是NullpointerException,因为尚未设置静态字段。为了解决这个问题,您可以使用信号量(或其他半音)来创建某种屏障。对于信号量,这将包括一个具有0个许可的简单信号量。在使用变量之前,先获取并释放它。设置完变量后(在此类之外),对其调用一次release。

这不是一个好的解决方案(就软件设计而言),但是应该可以解决问题。