12

I have an enum in the client part of a GWT application and I am getting an exception when I try to run it that is related to serialization problems. Am I doing anything wrong? I read that enums are supported by GWT and I am using the last version.

The enum:

public enum AnEnum implements Serializable {

    ITEM_A("Item a description"), ITEM_B("Item b description");

    private String description;

    private AnEnum(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}

The exception:

Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeWithCustomSerializer(ServerSerializationStreamWriter.java:742)
    ... 47 more
Caused by: com.google.gwt.user.client.rpc.SerializationException: Type '(...).client.(...).AnEnum' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.: instance = ITEM_A
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:610)
    at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:129)
    at com.google.gwt.user.client.rpc.core.java.util.Collection_CustomFieldSerializerBase.serialize(Collection_CustomFieldSerializerBase.java:43)
    at com.google.gwt.user.client.rpc.core.java.util.LinkedList_CustomFieldSerializer.serialize(LinkedList_CustomFieldSerializer.java:36)
    ... 52 more
AntonioJunior
  • 919
  • 2
  • 15
  • 32
  • what package is the enum in, and what paths are listed in gwt.xml's source tags? – antony.trupe Nov 17 '10 at 20:05
  • 1
    There definitely seems to be a problem/bug with enums and GWTRPC! I tested your code with GWT 2.0.3, and it works (a no-arg constructor isn't even required). But when I use `setDescription("new value")` before calling the service method, that change to `description` is **lost** during transfer to the server - i.e. the server sees `description` as still being set to "Item a description". I haven't tried it with the latest version of GWT, but maybe Google attempted to fix that problem for GWT 2.1, but introduced the serialization problem. – Chris Lercher Nov 17 '10 at 23:35
  • 7
    Just found something in the [documentation](http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunication.html) about this: "Enumeration constants are serialized as a name only; none of the field values are serialized." Therefore, it's probably not a good idea to use enums with mutable fields together with GWTRPC. – Chris Lercher Nov 17 '10 at 23:43

9 Answers9

15

Add IsSerializable interface, a default scoped no-arg constructor, and make sure its in one of the paths listed in the source tags in your gwt.xml file. <source path="client">

I really think the third suggestion is the issue; I remember having this issue before and it was because I had a dto outside the source paths.

You can have multiple source tags.

<source path="common" />
<source path="client" />

One pattern is to put persisted objects directly under com.mysite.common, and mashups of persisted items that get transferred over the wire in com.mysite.common.dto, and of course the client gui code is in client.

package com.mysite.client;

import java.io.Serializable;

import com.google.gwt.user.client.rpc.IsSerializable;

public enum AnEnum implements Serializable, IsSerializable {

    ITEM_A("Item a description"), ITEM_B("Item b description");

    private String description;

    AnEnum() {
    }

    AnEnum(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}
antony.trupe
  • 10,640
  • 10
  • 57
  • 84
  • I've already done that, and it doesn't work. Funny thing is that the application always worked with that enum. It stopped working when i changed the name of some of the enum constants, but there's nothing wrong about it. – AntonioJunior Nov 17 '10 at 20:23
  • 1
    Thank you! Your suggestion solved my problem. Even after I did what you suggested, it wasn't working. It turns out that I needed to clean my project in Eclipse to get it to work. – AntonioJunior Nov 18 '10 at 19:31
  • 1
    Oh, no... Actually, it was just a matter of luck. I ran the system several times and GWT didn't complain, and then I saw the exception again. Chris Lercher is right in the comment he left. – AntonioJunior Nov 19 '10 at 12:16
4

You can try this check list:

  1. Verify that the class has a default constructor (without arguments)
  2. Verify that the class implements Serializable or IsSerializable or implements an Interface that extends Serializable or extends a class that implement Serializable
  3. Verify that the class is in a client.* package or …
  4. Verify, if the class is not in client.* package, that is compiled in your GWT xml module definition. By default is present. If your class is in another package you have to add it to source. For example if your class is under domain.* you should add it to xml as . Be aware that the class cannot belong to server package! More details on GWT page: http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideModuleXml
  5. If you are including the class from another GWT project you have to add the inherits to your xml module definition. For example if your class Foo is in the package com.dummy.domain you have to add to the module definition. More details here: http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideInheritingModules
  6. If you are including the class from another GWT project released as a jar verify that the jar contains also the source code because GWT recompile also the Java source for the classes passed to the Client.

Font: http://isolasoftware.it/2011/03/22/gwt-serialization-policy-error/

HenioJR
  • 604
  • 1
  • 10
  • 17
1

i think you need a no arg constructor.

Nick Siderakis
  • 1,961
  • 2
  • 21
  • 39
1

Only names of enumeration constants are serialized by GWT's RPC. Field values are not serialized.

GWT:Server Communication:Serializable Types

jpleal
  • 161
  • 7
1

I been studying above to solve some GWT code written in 2008, when upgraded to GWT SDK 2.4.0 (with latest gxt*.jar) gives me:

[WARN] adempiereService: An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: com.google.gwt.user.client.rpc.SerializationException: Type 'org.idempiere.ui.gwt.client.util.AdempiereGXTUtil$LoginStage' was not included in the set of types which can be deserialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be deserialized.
    at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:315)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)

...

Caused by: com.google.gwt.user.client.rpc.SerializationException: com.google.gwt.user.client.rpc.SerializationException: Type 'org.idempiere.ui.gwt.client.util.AdempiereGXTUtil$LoginStage' was not included in the set of types which can be deserialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be deserialized.
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader.deserialize(ServerSerializationStreamReader.java:581)

That notorious class is as follows (edited to follow ideas given in this thread):

public class AdempiereGXTUtil {

    public enum LoginStage implements IsSerializable, Serializable {  
        LOGOUT,
        LOGIN,
        ISLOGGEDIN,
        ROLES,
        WRONGUSER,
        WRONGROLE;

        LoginStage(){
        }
    };

}

Thinking about Andrej's answer to add type to white-list but enum is not some new myType, right? Anyway here is some reference in the codebase (non-relevant fields removed):

public interface AdempiereService extends RemoteService {

    public static final String SERVICE_URI = "adempiereService";

    public static class Util {

        public static AdempiereServiceAsync getInstance() {

            AdempiereServiceAsync instance = (AdempiereServiceAsync) GWT
                    .create(AdempiereService.class);
            return instance;
        }
    }

...     
    public LoginStage getLoginStage();

with:

public interface AdempiereServiceAsync {

...
    public void getLoginStage(AsyncCallback<LoginStage> callback);

Originally the AdempiereGXTUtil did not implement IsSerializable, Serializable nor has empty constructor but putting them in above, and cleaning out project in Eclipse does not change the same errors. Eclipse version used is Indigo on Java 1.6 in a Mac Lion environment. Hoping to get more from this thread, which by the way is amazing in its technical depth.

Community
  • 1
  • 1
  • 1
    It seems that Andrej's solution linked above is the way to go. I solved it by wrapping the Enum away so that a normal serialized class is used instead. Then it does not hit the error anymore. I gave him a +1 at his post. Many thanks Andrej! If anyone wants to know it is his Dummy dummy(Dummy d) workaround (2nd post there). If anyone is asking i can post what edits i done to my code above. – Redhuan D. Oon Jan 11 '12 at 15:23
  • I have uploaded a youtube movie on how i used Andrej's idea and solved my issue above. http://youtu.be/gGqvM9pc4mg – Redhuan D. Oon Jan 12 '12 at 13:46
0

In this case, Enum cannot be in the class. You have to create an external Enum.

HenioJR
  • 604
  • 1
  • 10
  • 17
0

In Gwt 2.9, I also had a "was not included in the set of types which can be serialized" error on a class that contained a field of type java.util.EnumSet of a custom enum class. It turned out the issue was not my custom enum, but the EnumSet itself. After replacing the EnumSet with a HashSet or LinkedHashSet, serialization worked. Maybe this is related to this issue: https://github.com/gwtproject/gwt/issues/3319

Martin Rust
  • 91
  • 1
  • 4
0

See http://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes:

A type is serializable and can be used in a service interface if one of the following is true:

The type is primitive, such as char, byte, short, int, long, boolean, float, or double. The type an instance of the String, Date, or a primitive wrapper such as Character, Byte, Short, Integer, Long, Boolean, Float, or Double. The type is an enumeration. Enumeration constants are serialized as a name only; none of the field values are serialized. The type is an array of serializable types (including other serializable arrays). The type is a serializable user-defined class. The type has at least one serializable subclass. The type has a Custom Field Serializer

In your case the type is an enumeration, so it is meant to be serializable.

These days GWT has 2 serialisation policies: LegacySerializationPolicy and StandardSerializationPolicy.

The LegacySerializationPolicy has an issue serialising enums unless they implement IsSerializable. Normally StandardSerializationPolicy will be used unless the SerializationPolicyProvider cannot find the *.gwt.rpc file for some reason. If it cannot find the *.gwt.rpc file then it will write a warning that you will most likely get serialisation issues so I would suggest that you start looking in the error log to see if it had issues finding the *.gwt.rpc file and if so fix that.

Also on a side note you should not be mutating Enums, I recall that Joshua Bloch writes about that in his book Effective Java.

Yoseph
  • 730
  • 1
  • 7
  • 8
-1

a) You definitely need a no-op constructor for serialization.

b) You can either extend GWT' IsSerializable class or, if you want to use Java's Serialization interface you must setup a policy to allow this. There's a post related to this at How do I add a type to GWT's Serialization Policy whitelist?. Also, check the GWT sight for more information on IsSerializable vs. Serializable.

Community
  • 1
  • 1
karakuricoder
  • 1,065
  • 8
  • 8