2011-12-28 10 views
10

Sírvanse proporcionar alguna información básica de cómo se utiliza TypeLiteral de Google Guice o Java EE, Será muy útil si se explicaría el uso de un código simple, gracias de antemanoEl uso de TypeLiteral en Java

+0

TypeLiteral es parte del framework Guice de Google, no el API estándar de Java. He editado tu pregunta para reflejar eso. –

+0

@MichaelBorgwardt Mira [aquí] (http://docs.oracle.com/javaee/6/api/javax/enterprise/util/TypeLiteral.html). – Howard

+0

@Howard: Ah, no pensé en consultar directamente la biblioteca Java EE, y la clase Guice fue la primera en Google. Curiosamente, ambas clases tienen exactamente el mismo propósito. –

Respuesta

11

El objetivo de TypeLiteral en Guice es permitir enlazar clases e instancias a tipos genéricos (con los parámetros de tipo especificados) evitando los problemas derivados del hecho de que los genéricos no se reifican en Java, es decir, del hecho de que la borradura se oculta la diferencia entre SomeInterface<String> y SomeInterface<Integer> en tiempo de ejecución. TypeLiteral permite que el valor de un parámetro genérico sobreviva al borrado creando una subclase ad hoc del tipo genérico.

Ejemplo de uso de TypeLiteral:

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

Este se une un parámetro de tipo SomeInterface<String>-SomeImplementation clase.

Para obtener información general, eche un vistazo a this blog post en tokens de tipo super y then this one en tipos literales.

2

La clase TypeLiteral es una solución para el hecho de que no puede tener literales de clase para tipos genéricos. El API doc of Binder (esto es de Google Guice, pero la clase Java EE del mismo nombre tiene exactamente el mismo propósito) da un ejemplo de cómo se utiliza:

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

Esto especifica que cualquier referencia de auto-inyectada de tipo PaymentService<CreditCard> será implementado por la clase concreta CreditCardPaymentService, dejando la opción para PaymentService<Coupon> para ser implementada por una clase diferente clase. Sin TypeLiteral, esto no sería posible porque el compilador de Java aceptará PaymentService<CreditCard>.class, solo PaymentService.class.

Tenga en cuenta que esto también requiere el uso de subclases anónimas ({} después de new TypeLiteral<PaymentService<CreditCard>>()) para evitar el borrado de tipos.

2

Esta es una forma en que los chicos eluden el borrado de genéricos en java. Lo necesita, cuando quiere atar una implementación a la interfaz parametrizada (genérica). Encontrado cierto uso en docs Guice:

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

Este constructo es cierto extraño es la manera de enlazar un tipo parametrizado. Le dice a Guice cómo cumplir con una solicitud de inyección para un elemento de tipo PaymentService. La clase CreditCardPaymentService debe implementar la interfaz PaymentService. Actualmente, Guice no puede vincular o inyectar un tipo genérico, como Establecer; todos los parámetros de tipo deben estar completamente especificados.

4

Como cualquier cosa en Guice: la modularidad, la reutilización y la eliminación del texto estándar son conceptos básicos de todas las utilidades.

Por supuesto, cualquier cosa que hagas en Guice pueden ser imitados en Java - a costa de un montón de repetitivo ... Así que la verdadera pregunta es:

¿Cómo podemos usar TypeLiterals escribir más modular/componentes reutilizables?

El poder de TypeLiterals en Guice es que le permite referir implementaciones de un servicio sin definir qué servicio es.

Vamos a empezar con una simple lista en un programa donde tenemos muchos tipos de listas que se procesan differntly:

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

Ahora, ¿cómo debo procesar estas cadenas? En tiempo de ejecución, no hay forma de "saber" que es una lista de cadenas. Por lo tanto, a menudo veces que podrían crear una fábrica, como tal, que obtiene los objetos de procesamiento para mí:

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

Por lo tanto, puede ser que utilice una fábrica (con un montón de if/else o casos de declaraciones) para definir los procesadores para diferentes tipos de datos. Mi constructor, para el objeto que utiliza estos procesadores y que necesita tener acceso a diversas implementaciones del procesador, podría tener este aspecto:

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(...)); 

Todo bien hasta ahora ... Hasta que nos damos cuenta de que hay una manera mejor:

En el mundo de Guice, puedo olvidarme de escribir esta fábrica, más bien, puedo vincular explícitamente las clases a los procesadores. La ventaja de esto es que no hay dependencias estáticas, la clase que necesita usar implementaciones de procesador NO NECESITA ninguna dependencia estática en una fábrica, sino que las clases se inyectan directamente. Por lo tanto, puedo fácilmente definir una clase que utiliza dependencias complejas, sin tener que construir un constructor de fábrica consciente de clase ... Por lo tanto, tengo mucho menos repetitivo:

@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. 

Hay un buen tutorial sobre esto con las implementaciones de interfaz y ejemplos vinculantes, aquí: http://thejavablog.wordpress.com/2008/11/17/how-to-inject-a-generic-interface-using-guice/

Cuestiones relacionadas