Использование TypeLiteral в java

Пожалуйста, предоставьте некоторую базовую информацию о том, как TypeLiteral в Google Guice или Java EE используется, будет очень полезно, если бы это было объясняется с помощью простого кода, заранее спасибо

Ответ 1

Цель TypeLiteral в Guice - разрешить привязывать классы и экземпляры к общим типам (с указанными параметрами типа), избегая проблемы, возникающие из-за того, что дженерики не воссоединяются на Java, т.е. из-за того, что стирание скрывает разницу между SomeInterface<String> и SomeInterface<Integer> во время выполнения. TypeLiteral позволяет значение универсального параметра выдержать стирание путем создания специального подкласса родового типа.

Пример использования TypeLiteral:

bind(new TypeLiteral<SomeInterface<String>>(){})
    .to(SomeImplementation.class);

Это связывает параметр типа SomeInterface<String> с SomeImplementation.

Для получения некоторой справочной информации смотрите этот пост в блоге на токенах супертекста и затем этот по типу литералов.

Ответ 2

Как и все в Guice - модульность, повторное использование и удаление шаблона - это основные понятия всех утилит.

Конечно, все, что вы делаете в Guice, можно передразнивать на Java - ценой большого количества шаблонов Итак... реальный вопрос:

Как мы можем использовать TypeLiterals для записи более модульных/повторно используемых компонентов?

Сила TypeLiterals в Guice заключается в том, что она позволяет вам ссылаться на реализации службы, не определяя, что это за служба.

Давайте начнем с простого списка в программе, где у нас есть много типов списков, которые обрабатываются по-разному:

List<String> myStringList = new ArrayList<String>();

Теперь, как мне обрабатывать эти строки? Во время выполнения нет возможности "знать", что это список строк. Таким образом, часто я мог бы создать factory, например, чтобы получить для меня объекты обработки:

ProcessorFactory.get(String.class).process(myStringList); 

Таким образом, я могу использовать factory (с кучей операторов if/else или case) для определения процессоров для разных типов данных. Мой конструктор для объекта, который использует эти процессоры и который нуждается в доступе к различным реализациям процессора, может выглядеть так:

public MyClass(Processor<String> strProcessor, Processor<Integer> intProcessor)P
{
    //Simple enough, but alot of boiler plate is required to launch this constructor.
}

//and to invoke 
new MyClass(PRocessorFactory.get(....), ProcessorFactory.get(...)); 

Все хорошо до сих пор... Пока мы не поймем, что есть лучший способ:

В мире Guice я могу забыть о написании этого factory - скорее, я могу явно использовать классы BIND для процессоров. Преимущество этого заключается в том, что нет статических зависимостей - класс, который должен использовать USE-реализации процессора, не нуждается в какой-либо статической зависимости от factory -rather, классы непосредственно вводятся. Таким образом, я могу легко определить класс, который использует сложные зависимости, не создавая конструктор классов factory. Таким образом, у меня гораздо меньше шаблона:

@Inject
public MyClass(Processor<String> implStr, Processor<Integer> implInt)
{
   //Now , this method will work magically, because Guice is capable of  
   //Using the loaded modules, which define bindings between generics and their implementations
}

//Elsewhere I simply define a single guice module that does the binding, and make sure to load it before my application launches. 

В этом есть хорошее руководство по реализации интерфейса и примерам привязки, здесь: http://thejavablog.wordpress.com/2008/11/17/how-to-inject-a-generic-interface-using-guice/

Ответ 3

Класс TypeLiteral является обходным путем для того, что вы не можете иметь литералы классов для общих типов. API doc Binder (это от Google Guice, но класс Java EE с тем же именем имеет точно такую ​​же цель) дает пример использования:

 bind(new TypeLiteral<PaymentService<CreditCard>>() {})
     .to(CreditCardPaymentService.class);

Это указывает, что любой автоматически инжектированный справочник типа PaymentService<CreditCard> будет реализован конкретным классом CreditCardPaymentService, в результате чего опция для PaymentService<Coupon> будет реализована другим классом. Без TypeLiteral это было бы невозможно, потому что компилятор Java примет PaymentService<CreditCard>.class, только PaymentService.class.

Обратите внимание, что это также требует использования анонимных подклассов ({} после new TypeLiteral<PaymentService<CreditCard>>()), чтобы обойти стирание типа.

Ответ 4

Это способ, которым ребята обходят дженериками в java. Это вам нужно, когда вы хотите связать некоторую реализацию с параметризованным (общим) интерфейсом. Нашли некоторое использование в документах Guice:

 bind(new TypeLiteral<PaymentService<CreditCard>>() {})
     .to(CreditCardPaymentService.class);

Эта, по общему признанию, нечетная конструкция - это способ привязки параметризованного типа. Он сообщает Guice, как выполнять запрос на инъекцию для элемента типа PaymentService. Класс CreditCardPaymentService должен реализовать интерфейс PaymentService. В настоящее время Guice не может связывать или вводить общий тип, например Set; все параметры типа должны быть полностью указаны.