Roboguice (ну, Guice) на самом деле способен «вводить в интерфейс», вот что он предназначен для работы. Допустим, что у вас есть следующий код:
public class ExampleClass {
@Inject InterfaceType mExampleField;
...
Guice будет влиять на его конкретный подтип InterfaceType
вы свяжете InterfaceType
в конфигурации впрыска при инжектировать ExampleClass
экземпляра. Скажем, модуль инициализации ваш инжектор с выглядит следующим образом:
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, посетив его конфигурацию, как это:
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 !
});
, если вы хотите, чтобы сделать его немного меньше Hacky.
Так это выглядит, как вы пытаетесь десериализации в типе, который имеет поле объявленное из типа интерфейса, например:
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
}
}
моя проблема, когда я пытаюсь десериализации строки JSON, который содержит объект, который записывается в POJO в качестве интерфейса , он оставляет это как null, это устранит проблему? –
Это еще одна проблема, я обновил свой ответ с тем, как обратиться к нему в вашем случае использования. Также добавлена заметка о том, что вы можете использовать Guice bindings посетителей. – desseim