Pregunta

Tengo un método de productor CDI, que - dependiendo de algunas condiciones que no son relevantes para este ejemplo - crea objetos de diferentes tipos:

public class TestProducer {

  @Produces @TestQualifier
  public Object create(InjectionPoint ip) {
    if(something) {
      return "a String";
    } else {
      return Integer.valueOf(42);
    }
  }

pero cuando se utiliza este productor, siempre me sale un error en la situación followin:

@Named("test")
public class TestComponent {
   ...
   @Inject public void setA(@TestQualifier String stringValue) {
   ...
   @Inject public void setB(@TestQualifier Integer integerValue) {

Sólo funciona cuando el método del productor cree tiene el tipo esperado en la firma del método:

public class TestProducer {

  @Produces @SpringBean
  public String create(InjectionPoint ip) {

Ahora la cadena GET del inyecta correctamente, pero no tengo manera de generar también un número entero del método de productor. Pero esto es exactamente lo que quiero evitar, ya que el propio productor debe estar completamente genérico.

¿Estoy haciendo algo mal o no hay ninguna manera de conseguir el comportamiento que quiero?

¿Fue útil?

Solución

Toda la documentación CDI deja claro que la CDI hace typesafe de inyección de dependencia - y es una propiedad exaltado de CDI. En mi humilde opinión, lo que está tratando de hacer es justo lo CDI trata de evitar. Desea que el recipiente para Object yeso para cada tipo y CDI no funciona de esa manera.

Los puntos de inyección stringValue y integerValue sólo puede recibir un grano que tiene java.lang.String y java.lang.Integer en su lista de tipos de frijol respectivamente. java.lang.Object no satisface este criterio.

Tengo dos sugerencias. En primer lugar, ya que tiene dos o más puntos de inyección de diferentes tipos, crear dos o más productores métodos para que los tipos:

public class TestProducer {

  @Produces @TestQualifier
  public String createString(InjectionPoint ip) {
    if(something) {
      return "a String";
    } else {
      // Some other value
    }
  }

  @Produces @TestQualifier
  public int createInt(InjectionPoint ip) {
    if(something) {
      return 42;
    } else {
      // Some other value
    }
  }
// ...

Funciona si la condición something es sólo para comprobar el tipo del punto de inyección (lo que estoy de apuestas es el caso).

Sin embargo, si la condición something hace decidir el tipo de uso de otros criterios que el tipo del punto de inyección, que había sugerencia para hacer el "trabajo sucio" a sí mismo: Inyectar el valor devuelto en un punto de inyección Object-escrito y hace el molde de forma manual:

@Named("test")
public class TestComponent {
   ...
   @Inject public void setA(@TestQualifier Object value) {
       String stringValue = (String) value;

   ...
   @Inject public void setB(@TestQualifier Object value) {
       int intValue = (Integer) value;

El punto principal es que, a diferencia de algunos otros marcos de DI, CDI no funciona contra el sistema tipo Java - por el contrario, es en gran medida lo utiliza. No trate de luchar contra ella pero el uso de este aspecto de la CDI en su favor:)

Otros consejos

Un productor de Object es extraño de todos modos. No estoy seguro de si esto está prohibido por la especificación, o se trata de un error, pero creo que se puede hacer un poco de solución ingeniosa:

public class ValueHolder<T> {
    private T value;

    public T getValue() {
        return value;
    }
}

Y luego inyectar un ValueHolder<String> y ValueHolder<Integer>

Sus posible crear objetos genéricos con CDI produce así:

  // the wrapper class
    public class Wrapper<T> {
      public final T bean;
      public Wrapper(T bean){
        this.bean = bean;
      }
    }

    // the producer inside some class
    @Produces
    public <T> Wrapper<T> create(InjectionPoint p){
      // with parameter 'p', it is possible retrieve the class type of <T>, at runtime
    }


    // the bean example 1
    public class BeanA {
      public void doFoo(){
        // ...
      }
    }
    // the bean example 2
    public class BeanB {
      public void doBar(){
        // ...
      }
    }


    // the class that uses the produced beans
    public class SomeBean{

//// There on producer method, do you can retrieve the Class object of BeanA and BeanB, from type parameters of Wrapper.

      @Inject
      private Wrapper<BeanA> containerA;
      @Inject
      private Wrapper<BeanB> containerB;

      public void doSomeThing(){
         containerA.doFoo();
         containerB.doBar();
      }

    }

Obras de soldadura 2.2.0. Creo que funciona en algunas versiones anteriores también.

Sus métodos inicializadores buscarán un bean gestionado con tipos de API String e Integer, pero el bean método de productor sólo tiene tipo API (en el caso del método de productor, tipo de retorno) del objeto.

Se puede, por tanto, sólo el uso de objetos en su inicializador método inyecta campos y luego discriminar entre los tipos int el cuerpo del receptor, o simplemente envolverlos y el método de productor en un tipo real que puede devolver Cadenas o Int (pero yo' d evitar los medicamentos genéricos)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top