parameter with <f:viewParam> and FacesConverter from CDI

ε祈祈猫儿з 提交于 2019-12-25 11:50:24

问题


It's not clear to me why I'm getting this particular exception, it's a red-herring I think. The underlying problem could be related to the last line of the exception: MessageConverter.getAsObject..0 which should actually be 1501 (the Message ID). So, why does MessageConverter.getAsObject have the wrong id?

I think that this could be related to the Detail constructor, which is probably passing the wrong parameters to MessageConvert.getAsObject(), in particular the UIComponent object -- probably that reference needs to get instantiated.

relevant EL:

        <h:outputLink id="link1" value="detail.xhtml">
            <f:param name="id" value="#{m.getMessageNumber()}" />
             <h:outputText value="#{m.getMessageNumber()}" />
        </h:outputLink>

glassfish shows:

INFO: MessageConverter.getAsObject..1501
INFO: SingletonNNTP.forward..11
WARNING: 1501
java.lang.ArrayIndexOutOfBoundsException: 1501
    at java.util.Arrays$ArrayList.get(Arrays.java:2866)
    at net.bounceme.dur.nntp.SingletonNNTP.getMessage(SingletonNNTP.java:86)
    at net.bounceme.dur.nntp.MessageConverter.getAsObject(MessageConverter.java:21)
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:171)
    at javax.faces.component.UIViewParameter.getConvertedValue(UIViewParameter.java:394)
    at javax.faces.component.UIInput.validate(UIInput.java:960)
    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)

INFO: MessageConverter.getAsObject..0
INFO: SingletonNNTP.forward..11

MessageConverter, I think that this class is fine so far is it goes:

package net.bounceme.dur.nntp;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.mail.Message;

@FacesConverter("messageConverter")
public class MessageConverter implements Converter {

    private static final Logger logger = Logger.getLogger(MessageConverter.class.getName());
    private static final Level level = Level.INFO;
    private SingletonNNTP nntp = SingletonNNTP.INSTANCE;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        logger.log(level, "MessageConverter.getAsObject..{0}", value);
        Message message = nntp.getMessage(Integer.parseInt(value));
        return message;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        Message message = (Message) value;
        return String.valueOf(message.getMessageNumber());
    }
}

This is the problem class, Detail, with the constructor, in particular, being suspect:

package net.bounceme.dur.nntp;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.mail.Message;

@Named
public class Detail {

    private static final Logger logger = Logger.getLogger(Detail.class.getName());
    private static final Level level = Level.INFO;
    private int id = 0;
    private Message message = null;
    private SingletonNNTP nntp = SingletonNNTP.INSTANCE;

    public Detail() {
        MessageConverter mc = new MessageConverter();
        FacesContext fc = FacesContext.getCurrentInstance();
        String value = String.valueOf(id);
        UIComponent ui = null;
        Object obj = mc.getAsObject(fc, ui, value);
        message = (Message) obj;
    }

    public int forward() {
        logger.log(level, "Detail.forward..{0}", id);
        id = id + 1;
        logger.log(level, "..Detail.forward {0}", id);
        return id;
    }

    public int back() {
        logger.log(level, "Detail.back..{0}", id);
        id = id - 1;
        logger.log(level, "..Detail.back {0}", id);
        return id;
    }

    public Message getMessage() {
        return message;
    }

    public String getContent() throws Exception {
        return message.getContent().toString();
    }
}

reference:

viewparam-vs-managedpropertyvalue-param-id which doesn't quite seem to apply as I'm using CDI, @Named, and so cannot use @ManagedProperty, which is the "real" problem. I suppose I'm not seeing the CDI benefit, as @ManagedProperty looks very nice.

ProcessingGETRequestParameters has a, perhaps, key paragraph:

Yes, it's a @ManagedBean instead of @FacesConverter! How awkward, but it's not possible to inject an @EJB inside a @FacesConverter in order to do the DB interaction job. The same problem manifests when you use the CDI @Inject to inject a property, you'd need to use @Named instead of @FacesConverter. The Java EE/JSF/CDI guys are working on that for the future JSF 2.2 version, see also JSF spec issue 763. If you really need to have it to be a @FacesConverter (in order to utilize the forClass attribute, for example), then you can always manually grab the EJB from JNDI. See also the next chapter.

which, is, for my purposes, perhaps slightly off-topic as it's EJB related. However, perhaps that is the exact difficulty which I'm encountering?


回答1:


The converter is supposed to be used in the <f:viewParam>.

<f:viewParam name="id" value="#{detail.message}" converter="messageConverter" />

This will basically convert the request parameter id to object Message and then set it in the property behind #{detail.message}. You should only supply a setter for it in the Detail class, I don't see any one in your bean.

You should not do the conversion job in the constructor of Detail class. You should only have a Message property, not the id or nntp. Remove the entire constructor.

@Named
public class Detail {

    private Message message; 

    // Getters+setters+actions
}


来源:https://stackoverflow.com/questions/10061422/parameter-with-fviewparam-and-facesconverter-from-cdi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!