Вопрос

Я хочу использовать значения Enum в <h:selectManyCheckbox>. Отказ Фуловые ящики получают правильно, однако при выборе некоторых значений и отправляют их, их тип выполнения String, а не мошенничество. Мой код:

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

Класс USERCONTROLLER (Securityrole - это тип 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 вызывает метод Setroles, он содержит список типовых строк, а не тип Enum. Есть идеи? Спасибо!

Это было полезно?

Решение

Эта проблема конкретно не связана с Enums. У вас будет та же проблема с другими List Типы, для которых JSF встроенные преобразователи, например, List<Integer>, List<Double>, Etcetera.

Проблема заключается в том, что El управляет временем выполнения, и эта информация об общем виде теряется во время выполнения. Таким образом, по сути, JSF / EL ничего не знает о параметризованном типе List и по умолчанию String Если иное не указано явным Converter. Отказ Теоретически, было бы возможно использование неприятных отраженных взломов с помощью ParameterizedType#getActualTypeArguments(), но разработчики JSF / EL могут иметь свои причины не делать этого.

Вам действительно нужно явно определить конвертер для этого. Поскольку JSF уже отправляются со встроенным EnumConverter (который не используемый автоном в этом конкретном случае, потому что вы должны указать тип enum во время выполнения), вы можете просто расширить его следующим образом:

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

}

И используйте это следующим образом:

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

или

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

Немного более общего (и Hacky) решений было бы хранить тип enum в качестве атрибута компонента.

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

}

Это полезно на всех видах List<Enum> Использование преобразователя ID. genericEnumConverter. Отказ Для List<Double>, List<Integer>, И т. Д. Однажды использовал встроенные преобразователи javax.faces.Double, javax.faces.Integer и так далее. Встроенный преобразователь Enum является неподходящим из-за неспособности указать тип целевого enum (A Class<Enum>) с точки зрения стороны на. Утилита jsf Омнозащитные предлагает именно этот конвертер из коробки.

Обратите внимание, что для нормального Enum Собственность, встроенный EnumConverter Уже хватает. JSF активирует его автоматически со правым типом Enum Target.

Другие советы

В некоторых случаях Список мог просто быть массивом Что-то [, И в этом случае явный преобразователь не требуется.

Общий стиратель был умным способом положить дженерики на язык, не нарушая старые вещи, но теперь мы живем вечно с последствиями этого решения ...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top