Frage

Ich möchte Enum-Werte in einem <h:selectManyCheckbox> verwenden. Die Kontrollkästchen korrekt eingesetzt bekommen, aber wenn einige Werte auswählen und deren Übermittlung, deren Laufzeittyp ist String und nicht Enum. Mein Code:

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

Usercontroller-Klasse (Security ist ein Aufzählungstyp):

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

Wenn JSF die setRoles Methode aufruft, enthält es eine Liste vom Typ String, und nicht der Aufzählungstyp. Irgendwelche Ideen? Dank!

War es hilfreich?

Lösung

Dieses Problem spezifisch ist nicht auf Aufzählungen bezogen. Sie würden das gleiche Problem mit anderen List Typen haben, für die JSF-Wandler gebautet hat, z.B. List<Integer>, List<Double>, und so weiter.

Das Problem ist, dass EL arbeitet Laufzeit und die generischen Typinformationen zur Laufzeit verloren. Also im Grunde, JSF / EL weiß nichts über den parametrisierte Typen der List und standardmäßig auf String sofern nicht anders durch eine explizite Converter angegeben. Theoretisch wäre es möglich, mit Hilfe von ParameterizedType#getActualTypeArguments() , aber die JSF / EL-Entwickler können ihre Gründe haben, dies nicht zu tun.

Sie müssen wirklich explizit einen Konverter für diese definieren. Da JSF bereits Schiffe mit einem eingebauten EnumConverter ( die nicht nutzbare Standalone in diesem speziellen Fall, weil Sie den Aufzählungstyp während der Laufzeit angeben müssen), könnten Sie erweitern es wie folgt:

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

}

Und es wie folgt verwenden:

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

oder

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

etwas mehr generisch (und hacky) Lösung zur Speicherung des ENUM-Typs als Komponente Attribut sein würde.

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 ist einsetzbar auf allen Arten von List<Enum> mit Konverter ID genericEnumConverter. Für List<Double>, List<Integer> usw. würde man den eingebauten Wandler javax.faces.Double, javax.faces.Integer verwendet und so weiter haben. Der eingebaute Enum Wandler ist übrigens nicht geeignet aufgrund der Unfähigkeit auf das Ziel enum-Typen (a Class<Enum>) von der Betrachtungsseite zu spezifizieren. Die JSF-Utility-Bibliothek OmniFaces Angebote genau dieser Konverter aus der Box .

Beachten Sie, dass für eine normale Enum Eigenschaft, die builtin EnumConverter bereits genügt. JSF wird es automatisch mit dem Aufzählungstyp richtigen Ziel instanziiert.

Andere Tipps

In einigen Fällen ist die Liste könnte genausogut ein Array sein Sometype [] , und in diesem Fall keine explizite Wandler benötigt wird.

Allg Löschung war eine kluge Art und Weise Generika in die Sprache setzen, ohne die alten Sachen zu brechen, aber jetzt leben wir für immer mit den Folgen dieser Entscheidung ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top