Pregunta

Quiero utilizar los valores de enumeración en un <h:selectManyCheckbox>. Las casillas de verificación son rellenados correctamente, sin embargo, al seleccionar algunos valores y de su presentación, su tipo de tiempo de ejecución es String, y no de enumeración. Mi código:

<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
     <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

clase UserController (SecurityRole es un tipo enum):

public SelectItem[] getRolesSelectMany() {
    SelectItem[] items = new SelectItem[SecurityRole.values().length];

    int i = 0;
    for (SecurityRole role : SecurityRole.values()) {
        items[i++] = new SelectItem(role, role.toString());
    }
    return items;
}     

public List<SecurityRole> getRoles() {
     getCurrent().getRoles();
}

public void setRoles(List<SecurityRole> roles) {
     getCurrent().setRoles(roles);
}

Cuando se llama al método JSF setRoles, que contiene una lista de tipo String, y no el tipo de enumeración. ¿Algunas ideas? Gracias!

¿Fue útil?

Solución

Este problema no está específicamente relacionado con las enumeraciones. Usted tendría el mismo problema con otros tipos List para el que ha JSF incorporadas convertidores, por ejemplo, List<Integer>, List<Double>, etcétera.

El problema es que EL opera en tiempo de ejecución y que la información de tipo genérico se pierde durante el tiempo de ejecución. Así que en esencia, JSF / EL no sabe nada sobre el tipo parametrizado de la List y por defecto a menos que se especifique lo contrario String por un Converter explícita. En teoría, habría sido posible el uso de hacks reflexión desagradables con la ayuda de ParameterizedType#getActualTypeArguments() , pero el JSF / eL desarrolladores pueden tener sus razones para no hacerlo.

¿De verdad es necesario definir explícitamente un convertidor para esto. Desde JSF ya envía con una orden interna del EnumConverter ( que no es independiente utilizable en este caso particular, ya que tiene que especificar el tipo de enumeración en tiempo de ejecución), sólo podría extenderse de la siguiente manera:

package com.example;

import javax.faces.convert.EnumConverter;
import javax.faces.convert.FacesConverter;

@FacesConverter(value="securityRoleConverter")
public class SecurityRoleConverter extends EnumConverter {

    public SecurityRoleConverter() {
        super(SecurityRole.class);
    }

}

y el uso de la siguiente manera:

<h:selectManyCheckbox value="#{userController.roles}" converter="securityRoleConverter">
    <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

o

<h:selectManyCheckbox value="#{userController.roles}">
    <f:converter converterId="securityRoleConverter" />
    <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

un poco más genérico (y hacky) solución sería la de almacenar el tipo de enumeración como atributo componente.

package com.example;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

@FacesConverter(value="genericEnumConverter")
public class GenericEnumConverter implements Converter {

    private static final String ATTRIBUTE_ENUM_TYPE = "GenericEnumConverter.enumType";

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value instanceof Enum) {
            component.getAttributes().put(ATTRIBUTE_ENUM_TYPE, value.getClass());
            return ((Enum<?>) value).name();
        } else {
            throw new ConverterException(new FacesMessage("Value is not an enum: " + value.getClass()));
        }
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        Class<Enum> enumType = (Class<Enum>) component.getAttributes().get(ATTRIBUTE_ENUM_TYPE);
        try {
            return Enum.valueOf(enumType, value);
        } catch (IllegalArgumentException e) {
            throw new ConverterException(new FacesMessage("Value is not an enum of type: " + enumType));
        }
    }

}

Es utilizable en todo tipo de List<Enum> utilizando genericEnumConverter convertidor de ID. Para List<Double>, List<Integer>, etc uno hubiera utilizado el convertidores incorporados javax.faces.Double, javax.faces.Integer y así sucesivamente. El convertidor incorporado Enum es por la forma inadecuada debido a la incapacidad para especificar el tipo de enumeración objetivo (un Class<Enum>) del lado vista sobre. La biblioteca de utilidades JSF OmniFaces ofrece exactamente este convertidor la caja .

Tenga en cuenta que para una propiedad Enum normal, el EnumConverter incorporado ya basta. JSF instanciarlo automágicamente con la derecha tipo de enumeración de destino.

Otros consejos

En algunos casos, el Lista podría muy bien ser un array SomeType [] , y en este caso no se necesita ningún convertidor explícita.

borrado Genérico era una forma inteligente de poner los genéricos en la lengua sin romper el material antiguo, pero ahora vivo para siempre con las consecuencias de esa decisión ...

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