在Gson反序列化期间使用Dagger进行依赖注入

问题描述 投票:1回答:1

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

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

DaggerExampleComponent.builder().build().inject(this)

不会重复使用其他地方注入的单例 - 从我的理解,这是因为构建器实际上会创建一个新的ExampleComponent实例,它不了解现有的实例。

我的解决方法是在instance中保持静态ExampleComponent字段和getter,但我想知道是否有一种最佳实践,如何用另一种方法实现相同的事情。

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

java dependency-injection gson dagger
1个回答
0
投票

Disclaimer

我很久没和Dagger合作了。用一粒盐取下面的溶液!该解决方案适用于我本地。

没有Dagger ExampleComponent

问题的一个答案可能是,使用自定义的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。

使用Dagger

您也可以更改代码以在所述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();

UPDATE

由于新的信息,我建议增强现有的类,用于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。

由于我不知道实际的参数,在asume String中作为这个typeconverter的参数。在那里插入相应的类型。

为了有效地使用它,在代码中的某个地方(在完成任何数据库相关的东西之前),应该调用它:

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

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

这可能仍有问题。这是一个race condition,承认静态变量的null状态。如果很快调用数据库,结果将是NullpointerException,因为尚未设置静态字段。为了抵消这一点,你可以使用信号量(或任何semilliar)来创造某种障碍。使用信号量,这将包括一个允许0的简单信号量。在使用变量调用获取和释放之前。在设置变量之后(在此类之外),在其上调用release一次。

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

© www.soinside.com 2019 - 2024. All rights reserved.