3

I have a very strange error in my code. I am using iterators since the beginning of my project and I never had problems but here I can't understand what's going on.

I have a model class

public class MyObject implements Serializable{
    private static final long serialVersionUID = 1L;

    private int field1;
    private String field2;
    private List<OtherObject> field3;
    private Date field4
    ...
    // + Getters and setters
    // + Override equals method
}

A class with a parameters of MyObject type

public class FooClass implements Serializable{
    private static final long serialVersionUID = 1L;
    private List<MyObject> list;
    // + getters and setters
}

And I have an other class using MyObject

public class MyController {
    .....
    public static void AMethod(FooClass value) {
        List<MyObject> myList = value.getList();
        Iterator<MyObject> iterator = myList.iterator();
        while(iterator.hasNext()) {
            MyObject temp = iterator.next();  // error on this line
        }
    }
    ...
}

My objects are displayed in a JSF view by using the following code:

<p:selectCheckboxMenu value="#{fooClass.list}">
    <f:selectItems value="#{fooClass.listAll}" var="obj" 
                   itemValue="#{obj}" itemLabel="#{obj.field2}" />
</p:selectCheckboxMenu>

Here is the error I'm getting:

java.lang.ClassCastException: java.lang.String cannot be cast to com.MyObject

Have any got any suggestions?

skuntsel
  • 11,624
  • 11
  • 44
  • 67
Loric
  • 1,678
  • 8
  • 28
  • 48

1 Answers1

2

This happens because of 'design' of HTTP protocol: when request is sent to the server all data are sent as Strings. So, JSF interprets them as Strings as well, because you didn't explicitly tell that the object to be expected is of your particular class, in your case MyObject. This happens because EL that handles all view-model communicaion is based on reflection and you know that generics in Java is a compile-time phenomenon due to type erasure: generic information is not available at runtime.

So basically after you submit the form your list consists of plain String objects and not of your MyObject instances, as you seem to expect: generic information was replaced by JSF EL after form had been submitted. That's why you got ClassCastException. You can check the types of elements your list contains by yourself if you put a breakpoint on an action(listener) method, or setter method.

To resolve the situation you either need to explicitly tell JSF to use a Converter (by specifying converter attribute, or by nesting <f:converter> tag), or by switching to plain array (to MyObject[]) instead of a List<MyObject>.

You can find more information, as well as some solutions, in my answer to JSF and type safety question.

Community
  • 1
  • 1
skuntsel
  • 11,624
  • 11
  • 44
  • 67