You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Tom Hartwell <to...@gmail.com> on 2014/03/01 01:34:49 UTC

CXF/JAXB Serialization of Enum

Hi, I'm working with CXF 2.7.7 for JAX-WS and and having trouble with the
de-serialization of an Enum. We recently upgraded many of libraries, and
this particular code was not modified, so I'm guessing the handling of
Enums has changed enough that it breaks our current code.

I can add more details if needed, but the crux of the issue seems to be:

Looking at the data via Wireshark, the SOAP body comes in with

-snip-
<type>AREA</type>
-snip-

For a method with a signature:

createArea(int arg1, int arg2, AreaType type, int arg4, CustomObject[]
objects)

Everything serializes fine, but the AreaType instance comes through as null.


I've attempted to add XML binding annotations to the AreaType to no avail.
I also added an XmlAdapter to see if that would aid in the conversion. No
luck there.

This is very hard to test in isolation. I can successfully unmarshal
<type>AREA</type> with a simple test as recommended in a separate thread by
a JAXB/Moxy programmer after adding XmlRootElement annotation to the enum.

I came across anther post recommending a no-arg constructor in order for
JAXB to unmarshal, but the fact that the test below unmarshals it
correctly, makes me think something is up with CXF.

==== TEST ====

public class JaxbUnmarshallerTest {

private static final String XML = "<areaType>AREA</areaType>";

    public static void main(String[] args) throws Exception {

        JAXBContext jc = JAXBContext.newInstance(AreaType.class);


        Unmarshaller unmarshaller = jc.createUnmarshaller();

        unmarshaller.setEventHandler(new ValidationEventHandler() {


            @Override

            public boolean handleEvent(ValidationEvent validationEvent) {

                 System.out.println(validationEvent.getMessage());

                 //validationEvent.getLinkedException().printStackTrace();

                 return true;

            }


        });


        AreaType root = (AreaType) unmarshaller.unmarshal(new StringReader(
XML));

        System.out.print(root.toString());

    }

}

==== END TEST ====


Here is the AreaType enum:

public enum AreaType {

    CAMPUS(null),

    BUILDING(CAMPUS),

    FLOOR(BUILDING),

    AREA(FLOOR),

    ROOM(AREA),

    SUBROOM(ROOM);

    private final AreaType parent;


    private static Map<String, AreaType> stringToEnum = new HashMap<String,
AreaType>();


    static {

        for(AreaType t : values()) {

            stringToEnum.put(t.toString(), t);

        }

    }


    private AreaType(AreaType parent) {

        this.parent = parent;

    }


    public AreaType getChild() {

        for(AreaType t : values()) {

            if(this == t.getParent()) {

                return t;

            }

        }

        return null;

    }


    public AreaType getParent() {

        return parent;

    }


    public static AreaType fromString(String type) {

        return stringToEnum.get(type);

    }


    public static AreaType fromValue(String type) {

        return stringToEnum.get(type);

    }

}

Re: CXF/JAXB Serialization of Enum

Posted by Daniel Kulp <dk...@apache.org>.
On Mar 3, 2014, at 2:47 PM, Tom Hartwell <to...@gmail.com> wrote:

> I've started to debug in the source, but there are a ton of layers. I see
> that by the time it gets to AbstractJAXWSMethodInvoker.invoke the enum
> instance in the params argument is null, but tracing further up the stack
> than that, I'm having trouble determining why the unmarshalling is failing
> for this enum.
> 
> Thanks for any help in advance, I'll keep digging,

First off:  can you check if there is a recent version of asm.jar available on the classpath?    That can change the code path slightly.

The actual unmarshalling would be handled by JAXB, but then mapping that to parameters would be part of CXF.  Places to look:

WrapperClassInInterceptor - if asm is available, it should have created a wrapper class for the full method which includes all the arguments.   The WrapperClassInIntereptor would take the single object that JAXB unmarshalled and pulls out the individual params.     There is a line in there that looks like:

newParams = new MessageContentsList(helper.getWrapperParts(wrappedObject));

that would be  a good breakpoint.   Check the fields in the “wrappedObject” to make sure the Enum in not null there.    If it IS null, then the issue is likely with the generation of the wrapper object.   If the enum is not null, but it’s not present in the “newParams” list, then the problem is in the helper (which is also likely ASM generated).   


If asm is NOT present, then the interesting breakpoint is likely in DocLiteralInInterceptor.getPara where it tries to read each individual parameter.   

Hopefully the above can help narrow down where to start looking.


Dan




> Tom
> 
> 
> On Fri, Feb 28, 2014 at 4:34 PM, Tom Hartwell <to...@gmail.com>wrote:
> 
>> Hi, I'm working with CXF 2.7.7 for JAX-WS and and having trouble with the
>> de-serialization of an Enum. We recently upgraded many of libraries, and
>> this particular code was not modified, so I'm guessing the handling of
>> Enums has changed enough that it breaks our current code.
>> 
>> I can add more details if needed, but the crux of the issue seems to be:
>> 
>> Looking at the data via Wireshark, the SOAP body comes in with
>> 
>> -snip-
>> <type>AREA</type>
>> -snip-
>> 
>> For a method with a signature:
>> 
>> createArea(int arg1, int arg2, AreaType type, int arg4, CustomObject[]
>> objects)
>> 
>> Everything serializes fine, but the AreaType instance comes through as
>> null.
>> 
>> 
>> I've attempted to add XML binding annotations to the AreaType to no avail.
>> I also added an XmlAdapter to see if that would aid in the conversion. No
>> luck there.
>> 
>> This is very hard to test in isolation. I can successfully unmarshal
>> <type>AREA</type> with a simple test as recommended in a separate thread by
>> a JAXB/Moxy programmer after adding XmlRootElement annotation to the enum.
>> 
>> I came across anther post recommending a no-arg constructor in order for
>> JAXB to unmarshal, but the fact that the test below unmarshals it
>> correctly, makes me think something is up with CXF.
>> 
>> ==== TEST ====
>> 
>> public class JaxbUnmarshallerTest {
>> 
>> private static final String XML = "<areaType>AREA</areaType>";
>> 
>>    public static void main(String[] args) throws Exception {
>> 
>>        JAXBContext jc = JAXBContext.newInstance(AreaType.class);
>> 
>> 
>>        Unmarshaller unmarshaller = jc.createUnmarshaller();
>> 
>>        unmarshaller.setEventHandler(new ValidationEventHandler() {
>> 
>> 
>>            @Override
>> 
>>            public boolean handleEvent(ValidationEvent validationEvent) {
>> 
>>                 System.out.println(validationEvent.getMessage());
>> 
>>                 //validationEvent.getLinkedException().printStackTrace();
>> 
>>                 return true;
>> 
>>            }
>> 
>> 
>>        });
>> 
>> 
>>        AreaType root = (AreaType) unmarshaller.unmarshal(newStringReader(
>> XML));
>> 
>>        System.out.print(root.toString());
>> 
>>    }
>> 
>> }
>> 
>> ==== END TEST ====
>> 
>> 
>> Here is the AreaType enum:
>> 
>> public enum AreaType {
>> 
>>    CAMPUS(null),
>> 
>>    BUILDING(CAMPUS),
>> 
>>    FLOOR(BUILDING),
>> 
>>    AREA(FLOOR),
>> 
>>    ROOM(AREA),
>> 
>>    SUBROOM(ROOM);
>> 
>>    private final AreaType parent;
>> 
>> 
>>    private static Map<String, AreaType> stringToEnum = newHashMap<String, AreaType>();
>> 
>> 
>>    static {
>> 
>>        for(AreaType t : values()) {
>> 
>>            stringToEnum.put(t.toString(), t);
>> 
>>        }
>> 
>>    }
>> 
>> 
>>    private AreaType(AreaType parent) {
>> 
>>        this.parent = parent;
>> 
>>    }
>> 
>> 
>>    public AreaType getChild() {
>> 
>>        for(AreaType t : values()) {
>> 
>>            if(this == t.getParent()) {
>> 
>>                return t;
>> 
>>            }
>> 
>>        }
>> 
>>        return null;
>> 
>>    }
>> 
>> 
>>    public AreaType getParent() {
>> 
>>        return parent;
>> 
>>    }
>> 
>> 
>>    public static AreaType fromString(String type) {
>> 
>>        return stringToEnum.get(type);
>> 
>>    }
>> 
>> 
>>    public static AreaType fromValue(String type) {
>> 
>>        return stringToEnum.get(type);
>> 
>>    }
>> 
>> }
>> 
>> 

-- 
Daniel Kulp
dkulp@apache.org - http://dankulp.com/blog
Talend Community Coder - http://coders.talend.com


Re: CXF/JAXB Serialization of Enum

Posted by Tom Hartwell <to...@gmail.com>.
I've started to debug in the source, but there are a ton of layers. I see
that by the time it gets to AbstractJAXWSMethodInvoker.invoke the enum
instance in the params argument is null, but tracing further up the stack
than that, I'm having trouble determining why the unmarshalling is failing
for this enum.

Thanks for any help in advance, I'll keep digging,
Tom


On Fri, Feb 28, 2014 at 4:34 PM, Tom Hartwell <to...@gmail.com>wrote:

> Hi, I'm working with CXF 2.7.7 for JAX-WS and and having trouble with the
> de-serialization of an Enum. We recently upgraded many of libraries, and
> this particular code was not modified, so I'm guessing the handling of
> Enums has changed enough that it breaks our current code.
>
> I can add more details if needed, but the crux of the issue seems to be:
>
> Looking at the data via Wireshark, the SOAP body comes in with
>
> -snip-
> <type>AREA</type>
> -snip-
>
> For a method with a signature:
>
> createArea(int arg1, int arg2, AreaType type, int arg4, CustomObject[]
> objects)
>
> Everything serializes fine, but the AreaType instance comes through as
> null.
>
>
> I've attempted to add XML binding annotations to the AreaType to no avail.
> I also added an XmlAdapter to see if that would aid in the conversion. No
> luck there.
>
> This is very hard to test in isolation. I can successfully unmarshal
> <type>AREA</type> with a simple test as recommended in a separate thread by
> a JAXB/Moxy programmer after adding XmlRootElement annotation to the enum.
>
> I came across anther post recommending a no-arg constructor in order for
> JAXB to unmarshal, but the fact that the test below unmarshals it
> correctly, makes me think something is up with CXF.
>
> ==== TEST ====
>
> public class JaxbUnmarshallerTest {
>
> private static final String XML = "<areaType>AREA</areaType>";
>
>     public static void main(String[] args) throws Exception {
>
>         JAXBContext jc = JAXBContext.newInstance(AreaType.class);
>
>
>         Unmarshaller unmarshaller = jc.createUnmarshaller();
>
>         unmarshaller.setEventHandler(new ValidationEventHandler() {
>
>
>             @Override
>
>             public boolean handleEvent(ValidationEvent validationEvent) {
>
>                  System.out.println(validationEvent.getMessage());
>
>                  //validationEvent.getLinkedException().printStackTrace();
>
>                  return true;
>
>             }
>
>
>         });
>
>
>         AreaType root = (AreaType) unmarshaller.unmarshal(newStringReader(
> XML));
>
>         System.out.print(root.toString());
>
>     }
>
> }
>
> ==== END TEST ====
>
>
> Here is the AreaType enum:
>
> public enum AreaType {
>
>     CAMPUS(null),
>
>     BUILDING(CAMPUS),
>
>     FLOOR(BUILDING),
>
>     AREA(FLOOR),
>
>     ROOM(AREA),
>
>     SUBROOM(ROOM);
>
>     private final AreaType parent;
>
>
>     private static Map<String, AreaType> stringToEnum = newHashMap<String, AreaType>();
>
>
>     static {
>
>         for(AreaType t : values()) {
>
>             stringToEnum.put(t.toString(), t);
>
>         }
>
>     }
>
>
>     private AreaType(AreaType parent) {
>
>         this.parent = parent;
>
>     }
>
>
>     public AreaType getChild() {
>
>         for(AreaType t : values()) {
>
>             if(this == t.getParent()) {
>
>                 return t;
>
>             }
>
>         }
>
>         return null;
>
>     }
>
>
>     public AreaType getParent() {
>
>         return parent;
>
>     }
>
>
>     public static AreaType fromString(String type) {
>
>         return stringToEnum.get(type);
>
>     }
>
>
>     public static AreaType fromValue(String type) {
>
>         return stringToEnum.get(type);
>
>     }
>
> }
>
>