Menu

Deserializing an enum with int values

Help
Tom VH
2013-01-16
2013-03-19
  • Tom VH

    Tom VH - 2013-01-16

    Hi, we are creating a JSON REST client application that has to communicate with a service written in C#.
    Most things like difference in dates etc are solved pretty easily with the FlexJson library.

    But one thing doesn't: Enum values that are sent as an integer, which is the value received from the service, and that have to be mapped to their Java Enum value.

    The Java enum is ok, we can convert integers to the enum as long as the value exists of course.
    But we do not succeed to get the Flexjson to convert the value.

    One of the Enums is called FormState

    We wrote a custom Transformer let's call it OurEnumTransformer which extends AbstractTransformer and implements ObjectFactory.
    Upon deserialization we add the .use(Enum.class, OurEnumTransformer), if we don't we get an error like:
    Don't know how to convert 4 to enumerated constant of FormState, which makes sense as it is an integer and not a name of an enum value

    But we add the .use(…) we keep getting an error on deserialization:
    FormState lacks a no argument constructor.  Flexjson will instantiate any protected, private, or public no-arg constructor.

    But it does actually have a private parameterless constructor.

    Another thing is that a breakpoint that is set in the OurEnumTransformer is never hit.

    So can anyone help me why .use(Enum.class, OurEnumTransformer) does not work with an enum that has integer values?

    The code of the enum and factory is below

    public enum FormState {
        None(0),
        EditMode(1),
        SignedBySender(2),
        AddedToRide(4),
        SignedByTransporter(8),
        SignedByReceiver(16),
        DLT_UNKNOWN(-1);
        
        private int value;
        
        private FormState() {
            this.value= -1;
        }
    
        private FormState(int value) {
            this.value= value;
        }
        
        public int getValue()
        {
            return value;
        }
        
        private static final Map<Integer, FormState> intToTypeMap = new HashMap<Integer, FormState>();
        static
        {
            for(FormState type: FormState.values())
            {
                intToTypeMap.put(type.value, type); 
            }
            
        }
        public static FormState fromInt(int i) {
            FormState type = intToTypeMap.get(Integer.valueOf(i));
            if (type == null) 
                return FormState.DLT_UNKNOWN;
            return type;
        }
    }
    

    and

    public final class InnectisEnumTransformer extends AbstractTransformer implements
            ObjectFactory {
        @SuppressWarnings("rawtypes")
        @Override
        public Object instantiate(ObjectBinder context, Object value, Type targetType,
                Class targetClass) 
        {
            if(targetClass.equals(FormState.class))
                return FormState.fromInt((Integer)value);
            else if(targetClass.equals(TrajectState.class))
                return TrajectState.fromInt((Integer)value);
            else
                throw new JSONException(String.format("%s:  Don't know how to convert %s to enumerated constant of %s",
                                             context.getCurrentPath(), value, targetType));
        }
        @Override
        public void transform(Object arg0) {
            // TODO Auto-generated method stub
    
        }
    }
    
     
  • Charlie Hubbard

    Charlie Hubbard - 2013-01-16

    So I tried this out in a unit test and the good news is that it worked.  However, the bad news is I think you've stumbled onto a bug that is fixed in the main branch, but hasn't been released yet.  I told someone last week we'd release very soon, and I'm getting ready to do that now.  I'll probably release tonight or tomorrow morning so you can upgrade and get the latest and have this fixed very shortly.

     

Log in to post a comment.