Отказ
Я давно не работал с Кинжалом. Примите следующие растворы с добавлением соли! Решение сработало для меня локально.
Без 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.
Лично я предпочел бы, чтобы это решение не смешивало Даггер и Гсон.
Использование кинжала
Вы также можете изменить код для использования DaggerAppComponent в указанном JsonDeserializer следующим образом:
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 (класс, содержащий аннотированный метод), например:
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 в качестве аргумента для этого преобразователя типов. Введите там соответствующий тип.
Чтобы использовать это эффективно, где-то в коде (до того, как будут сделаны какие-либо вещи, связанные с базой данных), это должно быть вызвано:
Convert.singletonProvider = DaggerExampleComponent.builder().build();
Это позволит классу Convert видеть правильный DaggerAppComponent.
Возможно, с этим еще есть проблема. Это состояние гонки , определяющее нулевое состояние статической переменной. Если база данных будет вызвана в ближайшее время, результатом будет NullpointerException, так как статическое поле еще не установлено. Чтобы противодействовать этому, вы можете использовать семафор (или что-нибудь подобное), чтобы создать своего рода барьер. В случае семафора это будет простой семафор с 0 разрешениями. Перед использованием вызывающей переменной приобретите и отпустите ее. После того, как переменная была установлена (вне этого класса), вызовите release для нее один раз.
Это не очень хорошее решение (с точки зрения разработки программного обеспечения), но оно должно сработать.