JSF,Composite Component:使用默认属性值作为参数的方法调用

时间:2012-10-31 18:24:07

标签: jsf-2 composite-component

我是JSF的新手并且还在学习。我试着寻找下面描述的具体问题的解决方案,但我找不到任何东西。如果是因为我在寻找错误的东西,请指出我正确的方向,但希望这是一个没有得到回答的答案,答案可以使每个人受益。

以下示例说明了我遇到的问题。简化示例以关注问题并隐藏发生问题的实际项目的复杂性。

考虑以下页面/类:

  1. /resources/test/custom.xhtml;
  2. /test/CharsetProvider.java;
  3. /test/CharsetHello.java;
  4. /testWith.xhtml;
  5. /testWithout.xhtml;
  6. /resources/test/custom.xhtml

    这是具有一个默认值属性的复合组件。组件只需获取属性值并将其作为参数传递给下面描述的CDI bean,以获取用于输出的模型对象。

    <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:cc="http://java.sun.com/jsf/composite"
          xmlns:h="http://java.sun.com/jsf/html">
    
        <cc:interface>
            <cc:attribute name="charset"
                          default="#{charsetProvider.defaultCharset}"
                          type="java.nio.charset.Charset" />
        </cc:interface>
    
        <cc:implementation>
            <h:outputText value="#{charsetProvider.createCharsetHello(cc.attrs.charset).hello}"/>
        </cc:implementation>
    </html>
    

    测试/ CharsetProvider.java

    这是一个CDI bean,它只包含整个应用程序中使用的默认值,并且有一个方法可以创建一个用作组件模型的对象。我使用CDI bean而不是支持bean的原因是因为在我的特定项目中,需要在运行时注入默认值,但是支持bean不适合注入。

    package test;
    
    import java.nio.charset.Charset;
    import javax.annotation.PostConstruct;
    import javax.faces.bean.SessionScoped;
    import javax.inject.Named;
    
    @Named
    @SessionScoped
    public class CharsetProvider {
    
        private Charset defaultCharset;
    
        @PostConstruct
        protected void postConstruct() {
            this.defaultCharset = Charset.forName("UTF-8");
        }
    
        public Charset getDefaultCharset() {
            return defaultCharset;
        }
    
        public Charset getCharsetForName(String name) {
            return Charset.forName(name);
        }
    
        public CharsetHello createCharsetHello(Charset cs) {
            return new CharsetHello(cs);
        }
    }
    

    测试/ CharsetHello.java

    这是“模型”对象。它简单地转换为“Hello world!”到一个字节数组并使用给定的字符集返回。

    package test;
    
    import java.nio.charset.Charset;
    
    public class CharsetHello {
    
        private static final String HW = "Hello World!";
        private final byte[] data;
        private final Charset cs;
    
        public CharsetHello(Charset cs) {
            this.cs = cs;
            this.data = CharsetHello.HW.getBytes(this.cs);
        }
    
        public String getHello() {
            return new String(this.data, this.cs);
        }
    }
    

    testWith.xhtml

    这是一个测试页面,它通过指定组件属性的值来使用上面定义的复合组件。页面呈现正确,即“Hello World!”在屏幕上打印。

    <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:test="http://java.sun.com/jsf/composite/test">
        <h:head>
            <title>Test</title>
        </h:head>
        <h:body>
            <test:custom charset="#{charsetProvider.getCharsetForName('UTF-16')}" />
        </h:body>
    </html>
    

    testWithout.xhtml

    这是一个测试页面,它不会将自定义值传递给组件的属性,而是打算使用默认值。

    <?xml version='1.0' encoding='UTF-8' ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:test="http://java.sun.com/jsf/composite/test">
        <h:head>
            <title>Test</title>
        </h:head>
        <h:body>
            <test:custom />
        </h:body>
    </html>
    

    上面的页面会产生一个JSF错误页面,其中包含以下消息:

    /resources/test/custom.xhtml @14,94 value="#{charsetProvider.createCharsetHello(cc.attrs.charset).hello}": Cannot convert UTF-8 of type class java.lang.String to class java.nio.charset.Charset
    

    在最后一种情况下,默认值在传递给方法之前会转换为java.lang.String。

    首先,这是预期的行为,为什么?

    如果这是预期的行为,您能否提出不同的实施建议?

    提前谢谢!

1 个答案:

答案 0 :(得分:1)

此问题与此问题具有完全相同的基础:FacesConverter forClass don't work with Composite Componet。 Mojarra中的复合属性值类型被错误地评估为java.lang.Object,而不是实际的模型类型。

据报道为Mojarra issue 2568。它适用于MyFaces 2.1.9。