Question

Je veux utiliser des valeurs ENUM dans un <h:selectManyCheckbox>. Les cases à cocher se remplis correctement, cependant, lors de la sélection des valeurs et de les soumettre, leur type d'exécution est String, et non ENUM. Mon code:

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

classe UserController (SecurityRole est un type 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);
}

JSF appelle la méthode setRoles, il contient une liste de type String, et non le type enum. Des idées? Merci!

Était-ce utile?

La solution

Ce problème n'est pas lié spécifiquement à énumérations. Vous auriez le même problème avec d'autres types de List pour lesquels JSF a builtin convertisseurs, par exemple List<Integer>, List<Double>, etcetera.

Le problème est que EL fonctionne et que l'exécution des informations de type générique est perdue lors de l'exécution. Donc, en substance, JSF / EL ne sait rien sur le type paramétrées du List et par défaut String, sauf indication contraire par un Converter explicite. En théorie, il aurait été possible en utilisant hacks de réflexion désagréables avec l'aide de ParameterizedType#getActualTypeArguments() , mais le JSF / développeurs EL peuvent avoir leurs raisons pour ne pas faire cela.

Vous avez vraiment besoin de définir explicitement un convertisseur pour cela. Depuis JSF déjà livré avec un EnumConverter ( qui n'est pas autonome utilisable dans ce cas particulier parce que vous devez spécifier le type enum lors de l'exécution), vous pouvez simplement l'étendre comme suit:

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);
    }

}

et l'utiliser comme suit:

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

ou

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

Un peu plus de solution générique (et hacky) consisterait à stocker le type enum comme attribut du composant.

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));
        }
    }

}

Il est utilisable sur toutes sortes de List<Enum> utilisant genericEnumConverter ID convertisseur. Pour List<Double>, List<Integer>, etc on aurait utilisé les convertisseurs de BUILTIN javax.faces.Double, javax.faces.Integer et ainsi de suite. Le convertisseur intégré Enum est d'ailleurs inadaptés en raison de l'incapacité à spécifier le type cible enum (un Class<Enum>) à partir du côté de la vue sur. La bibliothèque utilitaire JSF OmniFaces offre exactement ce convertisseur la case .

Notez que pour une propriété Enum normale, la fonction interne EnumConverter suffit déjà. JSF instancier automagiquement avec le bon type de cible ENUM.

Autres conseils

Dans certains cas, la Liste pourrait tout aussi bien être un tableau UnType [] , et dans ce cas convertisseur ne explicite est nécessaire.

effacement générique est une façon intelligente de mettre les médicaments génériques dans la langue sans casser les vieux trucs, mais maintenant nous vivons toujours avec les conséquences de cette décision ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top