【问题标题】:Is there a way to get JSF to work with Generic setters and getters有没有办法让 JSF 与通用 setter 和 getter 一起工作
【发布时间】:2013-03-06 08:20:24
【问题描述】:

有没有办法让 JSF 与通用实体一起工作,如下所述:

Property.java

    public interface MyProperty<T> {
        void setMyValue(T value);
        T getMyValue(T value);
    }

在我的应用程序中,T 只能是 DateStringIntegerLong

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

有没有办法解决这个问题?

【问题讨论】:

    标签: java jsf jsf-2


    【解决方案1】:

    你的答案不清楚,但是,答案肯定是YES,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>
    

    【讨论】:

    • 您好,感谢您的回答。我添加了一些更多信息来试图澄清这个问题。希望现在这个问题更有意义。如果没有,请告诉我:-)
    猜你喜欢
    • 2020-03-09
    • 1970-01-01
    • 2013-03-27
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    相关资源
    最近更新 更多