是否有一种方法可以让JSF像下面描述的那样处理通用实体呢?
Property.java
public interface MyProperty<T> {
void setMyValue(T value);
T getMyValue(T value);
}
在我的应用中,T
只能使用Date
, String
, Integer
或Long
MyObject.java
public class MyObject {
List<MyProperty<?>> properties;
public List<MyProperty<?>> getProperties() {
return properties;
}
}
MyController.java
@Named("controller")
@RequestScoped
public class MyController {
MyObject myObject;
public void setMyObject(MyObject myObject) { this.myObject = myObject; };
public MyObject getMyObject() { return myObject; } ;
}
edit.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head><title></title></h:head><h:body>
<h:form>
<ui:repeat var="property" value="#{controller.myObject.properties}">
<h:inputText value="#{property.myValue}"/>
</ui:repeat>
<h:commandButton action="#{controller.save}" value="save"/>
</h:form>
</h:body>
</html>
不幸的是,这不起作用,因为JSF试图在myObject上找到一个带有签名的setter:
void setMyValue(String value);
显然不存在,因为类型擦除会导致方法具有以下签名:
void setMyValue(Object value);
有办法绕过这个吗?
您的回答不清楚,但是,答案肯定是是的, JSF可以伴随泛型。
不过,这取决于如何明智地使用泛型,最终取决于你是否完全理解泛型。
据我所知,从您的示例中,您将使用泛型接口作为包装器到所实现类中包含的对象。
使用包装的getter/setter类
使用这种方法,您不直接处理MyInterface
实现,而是处理其内容,如接口方法所定义的。
基本接口:
public interface MyInterface<T> {
void setMyValue(T value);
T getMyValue();
}
实现类:
public class MyString implements MyInterface<String> {
private String myValue;
public MyString(String myValue) {
this.myValue = myValue;
}
public void setMyValue(String value) {
this.myValue = value;
}
public String getMyValue() {
return myValue;
}
@Override
public String toString() {
return myValue;
}
}
和
public class MyInteger implements MyInterface<Integer> {
private Integer myValue;
public MyInteger(Integer myValue) {
this.myValue = myValue;
}
public void setMyValue(Integer value) {
this.myValue = value;
}
public Integer getMyValue() {
return myValue;
}
@Override
public String toString() {
return Integer.toString(myValue);
}
}
托管bean(带有匿名类):
@ManagedBean
@RequestScoped
public class MyInterfaceBean {
private MyString myString;
private MyInteger myInteger;
private MyInterface<Float> myFloat;
public MyInterfaceBean() {
myString = new MyString("String");
myInteger = new MyInteger(1);
myFloat = new MyInterface<Float>() {
private Float myValue;
public void setMyValue(Float value) {
this.myValue = value;
}
public Float getMyValue() {
return myValue;
}
@Override
public String toString() {
return Float.toString(myValue);
}
};
myFloat.setMyValue(3.1f);
}
public String getMyString() {
return myString.getMyValue();
}
public void setMyString(String myString) {
this.myString.setMyValue(myString);
}
public Integer getMyInteger() {
return myInteger.getMyValue();
}
public void setMyInteger(Integer myInteger) {
this.myInteger.setMyValue(myInteger);
}
public Float getMyFloat() {
return myFloat.getMyValue();
}
public void setMyFloat(Float myFloat) {
this.myFloat.setMyValue(myFloat);
}
public String action() {
return null;
}
}
视图:<h:outputText value="String: #{myInterfaceBean.myString}"/>
<br/>
<h:outputText value="Integer: #{myInterfaceBean.myInteger}"/>
<br/>
<h:outputText value="Float: #{myInterfaceBean.myFloat}"/>
<br/>
<h:form>
<h:outputText value="String: "/><h:inputText value="#{myInterfaceBean.myString}"/>
<br/>
<h:outputText value="Integer: "/><h:inputText value="#{myInterfaceBean.myInteger}"/>
<br/>
<h:outputText value="Float: "/><h:inputText value="#{myInterfaceBean.myFloat}"/>
<br/>
<h:commandButton value="Submit" action="#{myInterfaceBean.action}"/>
</h:form>
使用类@FacesConverter
另一种方法是使用@FacesConverter
,这样JSF就知道如何将输入字段中的字符串转换为实现MyInterface
的对象。
托管bean(带有匿名类):
@ManagedBean
@RequestScoped
public class MyInterfaceBean {
private MyString myString;
private MyInteger myInteger;
private MyInterface<Float> myFloat;
public MyInterfaceBean() {
myString = new MyString("String");
myInteger = new MyInteger(1);
myFloat = new MyInterface<Float>() {
private Float myValue;
public void setMyValue(Float value) {
this.myValue = value;
}
public Float getMyValue() {
return myValue;
}
@Override
public String toString() {
return Float.toString(myValue);
}
};
myFloat.setMyValue(3.1f);
}
public MyString getMyString() {
return myString;
}
public void setMyString(MyString myString) {
this.myString = myString;
}
public MyInteger getMyInteger() {
return myInteger;
}
public void setMyInteger(MyInteger myInteger) {
this.myInteger = myInteger;
}
public MyInterface<Float> getMyFloat() {
return myFloat;
}
public void setMyFloat(MyInterface<Float> myFloat) {
this.myFloat.setMyValue(myFloat.getMyValue());//not to lose this anonymous class, can substitute for other implementation directly
}
public String action() {
return null;
}
}
转换器:
@FacesConverter(value = "myStringConverter")
public class MyStringConverter implements Converter {
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null || value.equals("")) {
return null;
}
MyString obj = new MyString(value);
return obj;
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof MyString) || (value == null)) {
return null;
}
return ((MyString)value).getMyValue();
}
}
和
@FacesConverter(value = "myIntegerConverter")
public class MyIntegerConverter implements Converter {
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null || value.equals("")) {
return null;
}
MyInteger obj = null;
try {
Integer integer = Integer.valueOf(value);
obj = new MyInteger(integer);
} catch(NumberFormatException nfe) {
throw new ConverterException(new FacesMessage("Integer could not be parsed from string: " + value));
}
return obj;
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof MyInteger) || (value == null)) {
return null;
}
return ((MyInteger)value).getMyValue().toString();
}
}
和
@FacesConverter(value = "myFloatConverter")
public class MyFloatConverter implements Converter {
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null || value.equals("")) {
return null;
}
MyInterface<Float> obj = null;
try {
Float floatValue = Float.valueOf(value);
obj = new MyInterface<Float>() {
private Float myValue;
public void setMyValue(Float value) {
this.myValue = value;
}
public Float getMyValue() {
return myValue;
}
@Override
public String toString() {
return Float.toString(myValue);
}
};
obj.setMyValue(floatValue);
} catch(NumberFormatException nfe) {
throw new ConverterException(new FacesMessage("Float could not be parsed from string: " + value));
}
return obj;
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof MyInterface) || (value == null)) {
if(!(((MyInterface)value).getMyValue() instanceof Float)) {
return null;
}
}
return ((MyInterface)value).getMyValue().toString();
}
}
视图:<h:outputText value="String: #{myInterfaceBean.myString}"/>
<br/>
<h:outputText value="Integer: #{myInterfaceBean.myInteger}"/>
<br/>
<h:outputText value="Float: #{myInterfaceBean.myFloat}"/>
<br/>
<h:form>
<h:outputText value="String: "/><h:inputText value="#{myInterfaceBean.myString}" converter="myStringConverter"/>
<br/>
<h:outputText value="Integer: "/><h:inputText value="#{myInterfaceBean.myInteger}" converter="myIntegerConverter"/>
<br/>
<h:outputText value="Float: "/><h:inputText value="#{myInterfaceBean.myFloat}" converter="myFloatConverter"/>
<br/>
<h:commandButton value="Submit" action="#{myInterfaceBean.action}"/>
</h:form>