getAsString() jsf customed converter fails to convert object
Asked Answered
J

3

1

I created a custom converter for jsf. The getAsObject() works perfect but the getAsString() is returning an exception. I am not really sure where the problem is, and I have tried converting the object to string in different ways, but it keeps on returning exception.

This my converters code:

    @Named
public class ProductConverter implements Converter{

    @EJB
    private ProductEJB productEjb;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if(value== null )
        {
            throw new ConverterException("There was an error at getAsObject()");
        }

        int id = Integer.parseInt(value);
        return productEjb.findProductById(id);
    }

    @Override    
    public String getAsString(FacesContext context, UIComponent component, Object value) {        

        if (value == null || value.equals("")) 
        {
            return "";            
        }
        else
        {
            Integer id = ((Product)value).getProduct_id();
            return String.valueOf(id);
        }

    }

}

This is the Product class (Getters/Setters/equals()/hash() excluded for simplicity):

@Entity
@NamedQueries({
    @NamedQuery(name="findAllProducts", query = "SELECT p from Product p")

})
public class Product implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy= GenerationType.AUTO)
    private int product_id;
    private String name;
    private String description;
    protected byte[] imageFile;
    private Float price;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateAdded;        
    @ManyToOne
    private Category category_fk;
    @ManyToOne
    private SaleDetails saleDetails_fk;

This is stack I'm getting:

java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:504)
    at java.lang.Integer.parseInt(Integer.java:527)
    at com.lv.Controllers.Converters.ProductConverter.getAsObject(ProductConverter.java:30)
    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:1550)
    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:860)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
    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)

This is the jsf where I am using the converter:

<f:metadata>
    <f:viewParam name="product" value="#{productDelete.product}" converter="#{productConverter}"/>
</f:metadata>
Jolley answered 6/11, 2012 at 4:44 Comment(0)
E
5

Just don't throw an exception when null or an empty value is received. This makes no sense. They may represent legitimately valid values which just represent "no value". Just return null then. If you'd like to force requireness, then you should be using required="true" instead or any custom Validator, but just don't do that in a Converter.

You should throw the ConverterException only when the value is really unconvertable. I've improved your converter to do exactly that. You are namely not checking if the submitted value is a valid number nor if the obtained model value is an instance of Product. It would otherwise have caused NumberFormatException or ClassCastException further down in the code which you should have prevented beforehand by throwing the appropriate ConverterException.

@Named
public class ProductConverter implements Converter {

    @EJB
    private ProductEJB productEjb;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }

        if (!value.matches("\\d+")) {
            throw new ConverterException("The value is not a valid ID number: " + value);
        }

        int id = Integer.parseInt(value);
        return productEjb.findProductById(id);
        // You may want to perform an additional check if it didn't return null
        // and otherwise throw ConverterException with "unknown Product ID".
    }

    @Override    
    public String getAsString(FacesContext context, UIComponent component, Object value) {        
        if (value == null) {
            return null; // Or an empty string, can also.
        }

        if (!(value instanceof Product)) {
            throw new ConverterException("The value is not a valid Product: " + value);
        }

        Integer id = ((Product)value).getProduct_id();
        return (id != null) ? String.valueOf(id) : null;
    }

}
Ethic answered 6/11, 2012 at 16:5 Comment(1)
thank you very much, I have made the suggested changes to my converter and the problem has been fixed. I discovered some other errors. I got a javax.faces.el.EvaluationException: javax.ejb.EJBException , java.lang.IllegalArgumentException: Object: null is not a known entity type. and javax.ejb.EJBException. I will try to resolve them on my own, if I can t I will post a new question, to avoid mixing pears and apples. Once again thank you very much, I am new JSF and thanks to you I now better understand the structure of a converter.Jolley
P
2

Looks like your method cant handle when the value is null. Try returning an empty string in that case

public String getAsString(FacesContext facesContext, UIComponent component, Object value) {
    if (value == null || value.equals("")) {
        return "";
    } else {
        Integer id = ((Product)value).getProduct_id();
        return String.valueOf(id);
    }
}
Pope answered 6/11, 2012 at 9:26 Comment(1)
Thanks for your response. I have changed my code accordingly (following your example) however, I am now getting a java.lang.NumberFormatException: For input string: "". Do you have any ideas on how to fix this? I have updated the stack in the original posting, as well as my converter class. Thanks in advance.Jolley
R
1

The value expression #{productDelete.product} is resolving to null.

Note: the contract for a converter states that getAsString returns an empty string for null values.

Rocky answered 6/11, 2012 at 9:26 Comment(2)
Thanks you very much. I have reviewed the method detail explanation and made adjustments to the code reflecting contract for a converter. However, I got a new stack and it now returns the empty string as part of stack. I have updated my post reflecting the new results as well as the changes to my converter class. At a point it is referring to the getAsObject(), could that the problem is in the get as object?Jolley
@Jolley - getAsObject should perform the inverse operation to getAsString; it is still throwing an exception. See BalusC's answer.Rocky

© 2022 - 2024 — McMap. All rights reserved.