jsf - Cómo usar los valores enum en f: selectItem(s)
jsf-2 enums (4)
Quiero hacer un menú desplegable selectOneMenu para poder seleccionar un estado en mi pregunta. ¿Es posible hacer que f: selectItem sea más flexible teniendo en cuenta lo que sucede si el orden de las enumeraciones cambia, y si la lista era grande? ¿Y podría hacerlo mejor? ¿Y es posible "seleccionar" automáticamente el elemento que tiene la pregunta?
Clase Enum
public enum Status {
SUBMITTED,
REJECTED,
APPROVED
}
Entidad de pregunta
@Enumerated(EnumType.STRING)
private Status status;
JSF
<div class="field">
<h:outputLabel for="questionStatus" value="Status" />
<h:selectOneMenu id="questionStatus" value="#{bean.question.status}" >
<f:selectItem itemLabel="Submitted" itemValue="0" />
<f:selectItem itemLabel="Rejected" itemValue="1" />
<f:selectItem itemLabel="Approved" itemValue="2" />
</h:selectOneMenu>
<hr />
</div>
JSF tiene un convertidor incorporado para enum
, así que esto debería hacer:
@ManagedBean
@ApplicationScoped
public class Data {
public Status[] getStatuses() {
return Status.values();
}
}
con
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems value="#{data.statuses}" />
</h:selectOneMenu>
(nota: desde JSF 2.0 ya no hay necesidad de proporcionar un SelectItem[]
o List<SelectItem>
, también se List<SelectItem>
T[]
y List<T>
y se puede acceder al elemento actual mediante el atributo var
)
Si usa la biblioteca de utilidades JSF OmniFaces , puede usar <o:importConstants>
lugar de un bean.
<o:importConstants type="com.example.Status" />
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems value="#{Status}" />
</h:selectOneMenu>
Si tiene la intención de controlar las etiquetas también, puede agregarlas a la enumeración de Status
:
public enum Status {
SUBMITTED("Submitted"),
REJECTED("Rejected"),
APPROVED("Approved");
private String label;
private Status(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
con
<f:selectItems value="#{data.statuses}" var="status"
itemValue="#{status}" itemLabel="#{status.label}" />
O mejor, haga que el valor enum sea una clave de propiedad de un paquete de recursos localizado (se requiere EL 3.0):
<f:selectItems value="#{data.statuses}" var="status"
itemValue="#{status}" itemLabel="#{text[''data.status.'' += status]}" />
con esto en un archivo de propiedades asociado con el paquete de recursos #{text}
data.status.SUBMITTED = Submitted
data.status.REJECTED = Rejected
data.status.APPROVED = Approved
Para la localización también podemos usar esta solución:
public enum Status { SUBMITTED, REJECTED, APPROVED }
data.status.SUBMITTED=Submitted
data.status.REJECTED=Rejected
data.status.APPROVED=Approved
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems
value="#{data.statuses}"
var="status"
itemValue="#{status}"
itemLabel="#{text[''data.status.''.concat(status)]}" />
</h:selectOneMenu>
Por lo tanto, la ruta del recurso para las cadenas de localización no está codificada en Enum.
Puede usar <f:selectItems value="#{carBean.carList}" />
y devolver una lista de instancias de SelectItem
que envuelven la enumeración (use Status.values()
para obtener todos los valores posibles).
Puede usar la siguiente función de utilidad para obtener los valores enum y usarlos en SelectOneMenu
por ejemplo. No es necesario crear frijoles y métodos repetitivos.
public final class ElEnumUtils
{
private ElEnumUtils() { }
/**
* Cached Enumerations, key equals full class name of an enum
*/
private final static Map<String, Enum<?>[]> ENTITY_ENUMS = new HashMap<>();;
/**
* Retrieves all Enumerations of the given Enumeration defined by the
* given class name.
*
* @param enumClassName Class name of the given Enum.
*
* @return
*
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
public static Enum<?>[] getEnumValues(final String enumClassName) throws ClassNotFoundException
{
// check if already cached - use classname as key for performance reason
if (ElEnumUtils.ENTITY_ENUMS.containsKey(enumClassName))
return ElEnumUtils.ENTITY_ENUMS.get(enumClassName);
final Class<Enum<?>> enumClass = (Class<Enum<?>>) Class.forName(enumClassName);
final Enum<?>[] enumConstants = enumClass.getEnumConstants();
// add to cache
ElEnumUtils.ENTITY_ENUMS.put(enumClassName, enumConstants);
return enumConstants;
}
}
Regístrelo como una función el en un archivo taglib:
<function>
<description>Retrieves all Enumerations of the given Enumeration defined by the given class name.</description>
<function-name>getEnumValues</function-name>
<function-class>
package.ElEnumUtils
</function-class>
<function-signature>
java.lang.Enum[] getEnumValues(java.lang.String)
</function-signature>
</function>
Y finalmente llámalo así:
<p:selectOneMenu value="#{bean.type}">
<f:selectItems value="#{el:getEnumValues(''package.BeanType'')}" var="varEnum"
itemLabel="#{el:getEnumLabel(varEnum)}" itemValue="#{varEnum}"/>
</p:selectOneMenu>
De forma similar a la respuesta de BalusC, debe utilizar un paquete de recursos con etiquetas enum localizadas y, para obtener un código más limpio, también puede crear una función como getEnumLabel(enum)