参考我以前的问题,为什么 @PostConstruct 方法不可运行?
glassfish 给出:
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..
我之前得到了更好的输出,其中 bean 被实例化但使用默认值并且没有及时获取 URL 参数,因此一些字段被填充而一些没有。
如果我的 Java 代码不清楚,请告诉我不清楚的地方。例如,我知道没有更好的方法将字符串解析为整数。请参阅此处的评论。
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;
}
}
和观点:
<?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>
我对此的看法是,在 @PostConstruct 之后调用将 URL 参数作为方法参数的 getter/setter 方法,导致 bean 处于不确定状态。bean 已被实例化,但尚未使用 URL 参数中的值初始化字段。这一点,我无法确定 bean 是否已使用 URL 参数初始化。
以前我有输出,这更清楚,但目前我只能产生这个错误。
出于实际目的,我刚刚将@PostConstruct 方法的内容移动到 Detail.setId(String),这至少有效。查看 oracle文档,我只是没有直接看到这一点,但是我从这些文档中得出的含义是使用转换器,这也是之前建议的。
我更好奇而不是实际实现一个转换器,因为它似乎是一种非常复杂的方式来做一件简单的事情。但是,@PostConstruct 中的“逻辑”正确地属于转换器吗?
上面的代码不是我实际使用的,它只是针对这个问题,这就是为什么“逻辑”起作用的原因,不是在 @PostConstruct 方法中,而是在 setId() 方法中。