SeamFramework.orgCommunity Documentation

Capítulo 6. Métodos de productor

6.1. Ámbito de un método de productor
6.2. Inyección dentro de métodos de productor
6.3. Uso de @New con métodos de productor

Los métodos de productor nos permiten sobrepasar algunas limitaciones que se presentan cuando el administrador de Web Bean, en lugar de la aplicación, es responsable de instanciar objetos. También son la forma más fácil de integrar objetos que no son Web Beans dentro del entorno de Web Beans. (Veremos un segundo método en Capítulo 12, Definición de Web Beans utilizando XML.)

Según las especificaciones:

Un productor de Web Beans actúa como fuente de objetos a ser inyectados, donde:

  • los objetos que van a ser inyectados no necesitan ser instancias de Web Beans,

  • el tipo concreto de objetos a ser inyectado puede variar en tiempo de ejecución o

  • los objetos requieren alguna especificación de inicialización que no es realizada por el constructor de Web Bean

Por ejemplo, los métodos de productor nos permiten:

En particular, los métodos de productor nos permiten utilizar polimorfismo de tiempo de ejecución con Web Beans. Como hemos visto, los tipos de despliegue son una solución potente para el problema del polimorfismo de tiempo de despliegue. Sin embargo, una vez que el sistema es desplegado, la implementación de Web Bean es corregida. El método de productor no tiene dicha limitación:

@SessionScoped

public class Preferences {
    
    private PaymentStrategyType paymentStrategy;
    
    ...
    
    @Produces @Preferred 
    public PaymentStrategy getPaymentStrategy() {
        switch (paymentStrategy) {
            case CREDIT_CARD: return new CreditCardPaymentStrategy();
            case CHEQUE: return new ChequePaymentStrategy();
            case PAYPAL: return new PayPalPaymentStrategy();
            default: return null;
        } 
    }
    
}

Consider an injection point:

@Preferred PaymentStrategy paymentStrat;

Este punto de inyección tiene el mismo tipo de anotaciones de enlace que el método de productor, por lo tanto apunta al método de productor mediante las reglas de inyección usuales de Web Beans. El método del productor será llamado por el administrador de Web Bean a fin de obtener una instancia para servir a este punto de inyección.

.

El ámbito del método de productor está predeterminado a @Dependent, y así será llamado cada vez que el administrador de Web Bean inyecte este campo o cualquier otro campo que apunte al mismo método de productor. Así, podría haber múltiples instancias del objeto PaymentStrategy para cada sesión de usuario.

Para cambiar esta conducta, podemos agregar una anotación @SessionScoped a este método.

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy() {
    ...
}

Ahora, cuando el método de productor es llamado, el PaymentStrategy devuelto se enlazará con el contexto de sesión. El método de productor no será llamado otra vez en la misma sesión.

No hay un problema en potencia con el código anterior. Las implementaciones de CreditCardPaymentStrategy son instanciadas mediante el operador nuevo de Java. Los objetos instanciados directamente por la aplicación no pueden hacer uso de la inyección de dependencia y no tienen interceptores.

Si esto no es lo que deseamos podemos utilizar la inyección de dependencia dentro del método del productor para obtener las instancias de Web Bean:

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
                                          ChequePaymentStrategy cps,
                                          PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
        case CREDIT_CARD: return ccps;
        case CHEQUE: return cps;
        case PAYPAL: return ppps;
        default: return null;
    } 
}

Espere, ¿qué sucede si CreditCardPaymentStrategy es una petición en ámbito de Web Bean? Entonces el método del productor tiene el efecto de "promover" la instancia de petición en ámbito actual dentro del ámbito de sesión. ¡Esto casi seguro es un error! El objeto en ámbito de petición será destruido por el administrador de Web Bean antes de finalizar la sesión, pero la referencia al objeto se dejará "colgando" en el ámbito de sesión. Este error no será detectado por el administrador de Web Bean, entonces, ¡por favor tenga un cuidado especial al retornar instancias de Web Bean desde métodos de productor!

Hay por lo menos tres formas de corregir este error. Podemos cambiar el ámbito de la implementación CreditCardPaymentStrategy, pero podría afectar a otros clientes de ese Web Bean. Una mejor opción sería cambiar el ámbito del método del productor a @Dependent o @RequestScoped.

Pero una solución más común es utilizar la anotación especial de enlace @New.

Considere el siguiente método de productor:

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
                                          @New ChequePaymentStrategy cps,
                                          @New PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
        case CREDIT_CARD: return ccps;
        case CHEQUE: return cps;
        case PAYPAL: return ppps;
        default: return null;
    } 
}

Entonces una nueva instancia dependiente deCreditCardPaymentStrategy será creada, pasada al método de productor, devuelta por el método de productor y finalmente vinculada al contexto de sesión. El objeto dependiente no será destruido hasta que el objeto Preferencias sea destruido, al final de la sesión.