java - 有没有办法让 JSF 与通用 setter 和 getter 一起工作

标签 java jsf jsf-2

有没有办法让 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; } ;
}

编辑.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可以伴随泛型。

不过,这取决于您使用泛型的明智程度,并最终取决于您是否真正理解泛型。

据我从您的示例中可以看出,您将使用通用接口(interface)作为已实现类中包含的对象的包装器

使用带有包装的 getter/setter 的类

使用这种方法,您不直接处理 MyInterface 实现,而是处理其内容,如接口(interface)方法所定义。

基本接口(interface):

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

}

View :

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

}

View :

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

关于java - 有没有办法让 JSF 与通用 setter 和 getter 一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15242215/

相关文章:

Java 二维数组

未找到 Windows 上的 JavaFX 安装

java - 身份验证后以编程方式添加角色

Java EE 应用程序数据库架构

java - PrimeFaces barChart 未显示

java - 日志 spring Bean 实例化

java - java中的用户界面

jsf - 复合:clientBehavior ==> NotSerializableException: com. sun.faces.facelets.tag.jsf.core.AjaxHandler

jsf - c :set gets called multiple times instead of its return value being used 中的 EL 表达式

javascript - 使用 primefaces 访问 Jquery UI