Question

I am trying to add dynamic form fields to jsf form. But even following simple codes gives errors.

test.xhtml

<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<h:form id="form" binding="#{testBean.form}" />
<h:commandButton value="submit" action="#{testBean.submit}" />
</body>
</html>

Field.java

package Entity;

public class Field {

private String name;

public Field() {
    // TODO Auto-generated constructor stub
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

testBean.java

package beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.application.Application;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIInput;
import javax.faces.component.html.HtmlForm;
import javax.faces.component.html.HtmlInputText;
import javax.faces.context.FacesContext;

import Entity.*;

@ManagedBean
@ViewScoped
public class testBean implements Serializable{

    private static final long serialVersionUID = 770513161289990805L;
    private HtmlForm form = new HtmlForm();

    private List<Field> fields=new ArrayList<Field>(); 
    private Map<String, Object> values; 

    private Field field1 = new Field();
    private Field field2 = new Field();

    public testBean() {

        field1.setName("aaa");
        field2.setName("bbb");
        fields.add(field1);
        fields.add(field2);

        values = new HashMap<String, Object>();

    }

    private ValueExpression createValueExpression(String binding, Class clazz) {
        final ValueExpression ve = getExpressionFactory()
                .createValueExpression(getELContext(), binding, String.class);

        return ve;
    }

    public static ELContext getELContext() {

        return FacesContext.getCurrentInstance().getELContext();
    }

    public static ExpressionFactory getExpressionFactory() {

        return getApplication().getExpressionFactory();
    }

    public static Application getApplication() {

        return FacesContext.getCurrentInstance().getApplication();
    }

    @SuppressWarnings("el-syntax")
    public HtmlForm getForm() {
        if (form == null) {

            form = new HtmlForm();

            for (Field field : fields) {
                UIInput input = new HtmlInputText();
                input.setId(field.getName()); // Must be unique!
                String v = "#{testBean.values['" + field.getName() + "']}";
                input.setValueExpression("value",
                        createValueExpression(v, String.class));
                form.getChildren().add(input);

            }

        }
        return form;
    }

    public void setForm(HtmlForm form) {
        this.form = form;
    }

    public List<Field> getFields() {
        return fields;
    }

    public void setFields(List<Field> fields) {
        this.fields = fields;
    }

    public Map<String, Object> getValues() {
        return values;
    }

    public void setValues(Map<String, Object> values) {
        this.values = values;
    }

    public void submit() {
        System.out.println("Worked :)");
    }

}

My codes above gives "java.io.NotSerializableException: Entity.Field" error.

java.io.NotSerializableException: Entity.Field
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    java.util.HashMap.writeObject(Unknown Source)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeArray(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    java.util.HashMap.writeObject(Unknown Source)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    com.sun.faces.renderkit.ClientSideStateHelper.doWriteState(ClientSideStateHelper.java:325)
    com.sun.faces.renderkit.ClientSideStateHelper.writeState(ClientSideStateHelper.java:173)
    com.sun.faces.renderkit.ResponseStateManagerImpl.writeState(ResponseStateManagerImpl.java:122)
    com.sun.faces.application.StateManagerImpl.writeState(StateManagerImpl.java:166)
    com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
    com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:419)
    com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.12 logs.

If I make Field class Serializable it gives error again.

HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

java.io.NotSerializableException: javax.faces.component.html.HtmlForm
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    java.util.HashMap.writeObject(Unknown Source)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeArray(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    java.util.HashMap.writeObject(Unknown Source)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    java.io.ObjectOutputStream.writeObject0(Unknown Source)
    java.io.ObjectOutputStream.writeObject(Unknown Source)
    com.sun.faces.renderkit.ClientSideStateHelper.doWriteState(ClientSideStateHelper.java:325)
    com.sun.faces.renderkit.ClientSideStateHelper.writeState(ClientSideStateHelper.java:173)
    com.sun.faces.renderkit.ResponseStateManagerImpl.writeState(ResponseStateManagerImpl.java:122)
    com.sun.faces.application.StateManagerImpl.writeState(StateManagerImpl.java:166)
    com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
    com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:419)
    com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.12 logs.

Apache Tomcat/7.0.12

What is wrong with my simple code? Thanks in advance

Was it helpful?

Solution

Your bean is put in the view scope. A view scoped bean is stored in the HTTP session. Objects which are stored in the HTTP session needs to be Serializable, including all of its properties. However, an UI component like HtmlForm isn't serializable with the simple reason that its state is sensitive to request-based changes which would in case of being serializable only cause possibly corrupt/unsynced state after deserialization.

Basically, you need to put the bean in the request scope.

However, this entire approach is overcomplicated and flawed. Don't use <h:form binding>. Rather use a <h:dataTable> (or <ui:repeat> so you want). A complete kickoff example can be found in this answer: How to dynamically add JSF components

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top