简体   繁体   中英

use case for FacesConverter

Referencing a previous question of mine, why is the @PostConstruct method not runnable?

glassfish gives:

INFO: MessageBean..
INFO: MessageBean.getModel..
INFO: SingletonNNTP.getMessages..
INFO: MessageBean.getModel..
INFO: SingletonNNTP.getMessages..
INFO: SingletonNNTP.setIndex..2,205
INFO: SingletonNNTP.setIndex..2,205
INFO: SingletonNNTP.setIndex..2,206
INFO: SingletonNNTP.setIndex..2,206
INFO: SingletonNNTP.setIndex..2,207
INFO: SingletonNNTP.setIndex..2,207
INFO: SingletonNNTP.setIndex..2,208
INFO: SingletonNNTP.setIndex..2,208
INFO: SingletonNNTP.setIndex..2,209
INFO: SingletonNNTP.setIndex..2,209
INFO: SingletonNNTP.setIndex..2,210
INFO: SingletonNNTP.setIndex..2,210
INFO: SingletonNNTP.setIndex..2,211
INFO: SingletonNNTP.setIndex..2,211
INFO: SingletonNNTP.setIndex..2,212
INFO: SingletonNNTP.setIndex..2,212
INFO: SingletonNNTP.setIndex..2,213
INFO: SingletonNNTP.setIndex..2,213
INFO: SingletonNNTP.setIndex..2,214
INFO: SingletonNNTP.setIndex..2,214
INFO: SingletonNNTP.setIndex..2,215
INFO: SingletonNNTP.setIndex..2,215
INFO: MessageBean.getModel..
INFO: SingletonNNTP.getMessages..
INFO: Detail..
WARNING: /foo/detail.xhtml @9,67 value="#{detail.id}": org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] @PostConstruct public net.bounceme.dur.nntp.Detail.configBean() on net.bounceme.dur.nntp.Detail@c8e43a
javax.el.ELException: /foo/detail.xhtml @9,67 value="#{detail.id}": org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] @PostConstruct public net.bounceme.dur.nntp.Detail.configBean() on net.bounceme.dur.nntp.Detail@c8e43a
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
    at javax.faces.component.UIOutput.getValue(UIOutput.java:169)
    at javax.faces.component.UIInput.validate(UIInput.java:972)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
    at javax.faces.component.UIInput.processValidators(UIInput.java:698)
    at javax.faces.component.UIViewParameter.processValidators(UIViewParameter.java:273)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)
Caused by: org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] @PostConstruct public net.bounceme.dur.nntp.Detail.configBean() on net.bounceme.dur.nntp.Detail@c8e43a
    at org.jboss.weld.bean.AbstractClassBean.defaultPostConstruct(AbstractClassBean.java:508)
    at org.jboss.weld.bean.ManagedBean$ManagedBeanInjectionTarget.postConstruct(ManagedBean.java:174)
    at org.jboss.weld.bean.ManagedBean.create(ManagedBean.java:291)
    at org.jboss.weld.context.AbstractContext.get(AbstractContext.java:107)
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:90)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:79)
    at net.bounceme.dur.nntp.Detail$Proxy$_$$_WeldClientProxy.getId(Detail$Proxy$_$$_WeldClientProxy.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at javax.el.BeanELResolver.getValue(BeanELResolver.java:363)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:138)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:183)
    at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:224)
    at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    ... 38 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:264)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:52)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:137)
    at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:260)
    at org.jboss.weld.introspector.jlr.WeldMethodImpl.invoke(WeldMethodImpl.java:174)
    at org.jboss.weld.bean.AbstractClassBean.defaultPostConstruct(AbstractClassBean.java:506)
    ... 56 more
Caused by: java.lang.NumberFormatException: null
    at java.lang.Integer.parseInt(Integer.java:454)
    at java.lang.Integer.parseInt(Integer.java:527)
    at net.bounceme.dur.nntp.Detail.configBean(Detail.java:29)
    ... 66 more

INFO: Detail..

I was getting better output earlier, in which the bean was instantiated but with default values and not getting the URL parameters in time, so that some fields were populated and some not.

If my Java code is unclear, please let me know in what way it's unclear. I know of no better way to parse String to Integer, for example. See comments here .

package net.bounceme.dur.nntp;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import javax.mail.Message;

@Named
@ConversationScoped
public class Detail implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(Detail.class.getName());
    private String id = null;
    private Message message = null;
    private SingletonNNTP nntp = SingletonNNTP.INSTANCE;
    private int forward = 0;
    private int back = 0;

    public Detail() {
        LOG.info("Detail..");
    }

    @PostConstruct
    public void configBean() {
        int intId = Integer.parseInt(id);
        try {
            nntp.setIndex(intId);
            message = nntp.getMessage();
        } catch (Exception ex) {
            LOG.info("Detail.configBean..failed to set message");
        }
        setForward(intId + 1);
        setBack(intId - 1);
    }

    public Message getMessage() throws Exception {
        LOG.info("Detail.getMessage.." + getId());
        return message;
    }

    public void setMessage(Message message) {
        LOG.info("Detail.setMessage..");
        this.message = message;
    }

    public String getId() throws Exception {
        LOG.info("Detail.getId.." + id);
        if (id == null) { //should never be null, should get from URL as param
            LOG.info("..setting default id");
            id = String.valueOf(2000);
        }
        return id;
    }

    public void setId(String id) throws Exception {
        LOG.info("Detail.setId.." + id);
        this.id = id;
    }

    public int getForward() throws Exception {
        LOG.info("Detail.getForward.." + forward);
        return forward;
    }

    public void setForward(int forward) {
        LOG.info("Detail.setForward.." + forward);
        this.forward = forward;
    }

    public int getBack() throws Exception {
        LOG.info("Detail.setBack.." + back);
        return back;
    }

    public void setBack(int back) {
        LOG.info("Detail.setBack.." + back);
        this.back = back;
    }
}

and the view:

<?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:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        <f:metadata>
            <f:viewParam name="id" id="id" value="#{detail.id}" />
        </f:metadata>
        <ui:composition template="./complexTemplate.xhtml">
            <ui:define name="top">
                <div style="float: left">
                    <h:link value="back" outcome="detail" includeViewParams="true">
                        <f:param name="id" value="#{detail.back}"/>
                    </h:link>
                </div>
                <div style="float: right">
                    <h:link value="forward" outcome="detail" includeViewParams="true">
                        <f:param name="id" value="#{detail.forward}"/>
                    </h:link>
                </div>
                <p align="center"><h:outputText value="#{detail.message.messageNumber}" /></p>
            </ui:define>
            <ui:define name="left">
                <h:outputText value="#{detail.message.sentDate}" /><p/>
                <h:outputText value="#{detail.message.subject}"/><p/>
            </ui:define>
            <ui:define name="right">
            </ui:define>
            <ui:define name="content">
                <h:outputText value="#{detail.message.content}" escape="false"/>
            </ui:define>
            <ui:define name="bottom">
            </ui:define>
        </ui:composition>
    </body>
</html>

My take on this is that the getter/setter methods which take URL parameters as method arguments are invoked after @PostConstruct resulting in a bean in an indeterminate state. The bean has been instantiated but the fields have not been initialized with values from the URL parameters. This, there's no way which I'm aware of to determine whether the bean has been initialized or not with URL parameters.

Previously I had output where this was clearer, but at the moment I can only generate this error.

For practical purposes, I've just gone and moved the contents of the @PostConstruct method to the Detail.setId(String), which at least works. Looking at the oracle docs , I just don't see this directly covered, however the implication I draw from those docs is to use a Converter, which was also suggested previously.

I'm more curious than likely to actually implement a Converter, as it just seems a quite complex way of doing a simple thing. However, the "logic" in @PostConstruct rightly belongs in a Converter?

The above code isn't what I'm actually using, it's just for this question, which is why the "logic" works, not in the @PostConstruct method, but instead the setId() method.

Trying to use @PostConstruct was pointless because, from what I gather, that method executes prior the CDI magic where the params are read.

Ooops, then the spec must be wrong :) Mate, your code looks like a mess and the same might be true for your project-setup?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM