2014-01-22 1 views
0

Я использую RoboGuice и Gson в моем приложенииКак получить привязок roboguice в

в какой-то момент, мне нужно gson, чтобы ввести JSON в интерфейс, однако, Gson не знает, как придать интерфейс, если вы не предоставите создатель экземпляра, который сопоставляет между классом реализации и его интерфейсом

так же, как и с roboguice, ему также нужно это точное сопоставление.

, чтобы проверить мое заявление, я хочу дать roboguice и gson то же отображение реализации

как я ухватить связанные реализации roboguice в моих интерфейсах, для того, чтобы передать их в GsonBuilder InstanceCreator?

ответ

0

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 
    } 
} 
+0

моя проблема, когда я пытаюсь десериализации строки JSON, который содержит объект, который записывается в POJO в качестве интерфейса , он оставляет это как null, это устранит проблему? –

+0

Это еще одна проблема, я обновил свой ответ с тем, как обратиться к нему в вашем случае использования. Также добавлена ​​заметка о том, что вы можете использовать Guice bindings посетителей. – desseim

 Смежные вопросы

  • Нет связанных вопросов^_^