owlike/genson

JAXBBundle - Add support for @XmlElementWrapper

Opened this issue · 4 comments

voyko commented
JAXBBundle - Add support for @XmlElementWrapper

Can you please describe your use case? It would help me to better understand why you want this feature and how you would use it.

voyko commented

To achieve greater compatibility between the structure of the JSON data and XML.

Simple example (jersey):

@GET
@Path( "/items" )
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } )
public ItemsResult getItems()
{
   ItemsResult result = new ItemsResult();
   result.items = new String[ 2 ];
   result.items[ 0 ] = "A";
   result.items[ 1 ] = "B";

   return result;
}
@XmlAccessorType( XmlAccessType.NONE )
@XmlType( name = "" )
@XmlRootElement( name = "items_result" )
public final class ItemsResult
{
   @XmlElementWrapper( name = "items" )
   @XmlElement( name = "item" )
   public String items[];
}

XML result:

<items_result>
   <items>
      <item>A</item>
      <item>B</item>
   </items>
</items_result>

JSON result:

{"item": [
   "A",
   "B"
]}

I expected result:

{"items": {"item": [
   "A",
   "B"
]}}

To get the same structure result in XML and JSON, I need to define two classes.
First:

@XmlAccessorType( XmlAccessType.NONE )
@XmlType( name = "" )
@XmlRootElement( name = "items_result" )
public final class ItemsResult
{
   @XmlElement( name = "items" )
   public Items items = new Items();
}

Second:

@XmlAccessorType( XmlAccessType.NONE )
@XmlType( name = "" )
public class Items
{
   @XmlElement( name = "item" )
   public String items[];
}

I don't think that trying to mimic XML structure in json is a good thing.
In XML we can't represent an array, so that is why this pattern of items ->
item emerged.
It is sad to do the same ugly things in Json when you don't have to...

Do you have an actual use case where you need this structure? By need, I
mean that without it things wouldn't work.
It is on purpose that I initially didn't want to implement this feature
because I consider it as a very bad practice and didn't want to encourage
Genson users to do that...

About the expected structre, isn't it more like this?

{
  "items": [
     {"item": "A"},
     {"item": "B"}
  ]
}

esrat commented

Hello,
I found this issue by trying to solve a concrete problem. - So, I think I'm capable of providing the desired use case to support the initial feature request:
I’m currently working on a big project whose model classes are used under many circumstances (e.g. file import / export and SOAP services) - and therefore should not be changed for just introducing another use case.
Existing use cases do use JAXB for the serialization. Therefor the classes are annotated with e.g. @XmlElement AND @XmlElementWrapper for attributes with collection types. This does not only work for SOAP-interfaces using XML but also for another side project creating a REST-interface under IBM BlueMix.
Sadly I do not know how the BlueMix-project manages the serialization; but still this shows that it is possible to serialize these fully JAXB-annotated classes into JSON.

For my addition to this big, existing project, I am creating another REST-service on a Tomcat application server. I was already able to respond with simple strings to my REST-requests but got errors when trying to answer with complex types ("Jersey: A message body writer for Java Class and MIME mediatype application/json was not found"). I felt lucky to find Genson which was advertised as zero-configuration-usable. I only had to add its package path to the jersey packages to let it find the GensonJsonConverter as a provider class. From now on I could return simple collections like a set of strings and trust Genson to serialize them to JSON.
-> But I am still not able to use any model class using attributes with collection types! This always results in a

java.lang.ClassCastException: Inavlid XmlElement annotation, java.util.Set<Xyz> is not assignable from class Xyz
	com.owlike.genson.ext.jaxb.JAXBBundle$JaxbBeanPropertyFactory.getType(JAXBBundle.java:343)
	[...]

for the first such attribute.

If this is really by design, it looks like a cannot use Genson after all? :-(