Hi Matt Thanks for confirming it. I'm working in background on making sure one can do pretty much any sort of transformation (well, most simple enough transformations :-)) to JAXB-based outputs without having to deal with writing XMLStreamWriters/Readers but it will take me a bit of time. In 2.2.4 you can have namespaces dropped for JSON production only, to append them back you'd need to register a custom XMLStreamReader - it won't be needed once I'm done with my work.
It all goes pretty well for JAXB/XML but Jettison writer/reader need some fixes along the way; I'll work with the local Jettison build (with your patch being included) Cheers, Sergey mraible wrote: > > I was able to get everything working by changing @XmlAttribute to > @XmlElement and setting namespace="" to many elements. I'm not sure if > this is a workable solution on my project since we're using JAXB for XML > and I think the namespaces need to be there for that. > > For CXF 2.2.4, will it be possible to drop the namespaces for JSON > production/consumption only? Or will it affect XML as well? > > As far as the patch I submitted to Jettison, that is necessary to get JSON > to show up in the proper hierarchy. Without it, some children show up in a > parent where they shouldn't. > > Thanks, > > Matt > > > Sergey Beryozkin-2 wrote: >> >> Hi >> >> Having @XmlAttribute annotations causes Jettison to fail to deserialize >> the sequence you posted originally given that it causes it to serialize >> "@name":"bar" like properties in the first place. So I was able to write >> a test reading the sequence with CXF 2.2.3 as suggested in [1] (but I >> also had to ensure only the first root element was namespace-qualified). >> >> I've been working in background on making sure a user can customize most >> of the serialization process for JAXB/JSON (drop namespaces - possible >> in 2.4-SNAPSHOT, have a given node serialized with a diff local name, >> with/without namespace), additionally for JSON : cause attributes be >> serialized as elements, etc but I'll most likely won't finish it in time >> for 2.2.4 >> >> By the way, how does the patch for [2] helps in dealing with this issue >> ? >> >>> Is this bug something that would affect other JSON providers like >> Jackson >> too? >> >> Probably not - but I'm not exactly sure >> >>> I've heard it's 10x faster >> >> Possibly. Jettison does not do streaming which is something Dejan might >> get a chance to look into. >> >> Cheers, Sergey >> >> [1] >> http://www.nabble.com/Issues-marshalling-a-JSON-String-to-Java-Objects-( >> works-fine-from-Java-to-JSON)-tt25531242.html#a25775811 >> [2] http://jira.codehaus.org/browse/JETTISON-57 >> >> -----Original Message----- >> From: mraible [mailto:[email protected]] >> Sent: 06 October 2009 21:14 >> To: [email protected] >> Subject: Re: Issues marshalling a JSON String to Java Objects (works >> fine from Java to JSON) >> >> >> Sorry for not replying sooner - I thought I was subscribed to this >> thread in >> Nabble, but apparently wasn't. >> >> From your explanation, it sounds like I should try using CXF >> 2.2.4-SNAPSHOT >> and changing some annotations to @XmlElement. Is that correct? >> >> Is this bug something that would affect other JSON providers like >> Jackson >> too? I've heard it's 10x faster[1] and since I current have a patched >> version of Jettison[2], it might make sense to switch. >> >> Lastly, is there a JIRA issue for this that I can track or reference? >> >> Thanks, >> >> Matt >> >> [1] http://markmail.org/message/btngjg67rithzcv5 >> [2] http://jira.codehaus.org/browse/JETTISON-57 >> >> >> Sergey Beryozkin wrote: >>> >>> Jettison is uncapable of deserializing sequences containing something >> like >>> "@name":"foo". >>> So if you can change @XmlAttribute to @XmlElement then it would help. >>> Now, the other Jettison issue in this example in that it is only >> capable >>> of dealing with this sequence only if 'd.' is appended to the root >>> 'definition' element but not to 'structure'. So if you can update the >>> annotations such that only the root 'DataDefinition' class has the >>> namespace or no namespace at all then it would help too. >>> >>> >>> So you should end up with a sequence like this one : >>> >>> {"definition": {"repeating":"false","index":"0","name":"Credit Line >>> Increase Data", >>> >>> >> "structure":[{"repeating":"false","index":"2","name":"CreditLineIncConve >> rsation", >>> "symbolic":[ >>> {"index":"0","name":"ReasonForIncrease"}, >>> {"index":"4","name":"TermConds"} >>> ] >>> }] >>> } >>> } >>> >>> (note that the structure is an array [] now). >>> >>> There're a lot of preconditions there. in 2.2.4-SNAPSHOT it is >> possible to >>> tell a JSONProvider to drop namespaces. More customization will be >> coming >>> in later on to deal with the attributes issue and to ensure sequences >> can >>> be deserialized into JAXB beans with XmlRootElement containing >> namespaces. >>> >>> cheers, Sergey >>> >>> >>> Sergey Beryozkin wrote: >>>> >>>> Actually, I have reproduced it. It reads ok for JAXB but not for >> JSON. My >>>> initial thinking is that it is a Jettison (reader) bug, but I'll need >> to >>>> play more with this example before I can tell for sure. >>>> In meantime, you might want to try a Jackson JAXRS provider instead, >>>> Benson has added the test : >>>> >>>> >> http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/resour >> ces/jaxrs_jackson_provider/WEB-INF/beans.xml >>>> Or may be wrapping this one : >> http://code.google.com/p/json-framework/ >>>> >>>> Perhaps trying to simplify the class hierarchy or JAXB annotations >> might >>>> also make the difference. >>>> >>>> cheers, Sergey >>>> >>>> >>>> Sergey Beryozkin wrote: >>>>> >>>>> Hi >>>>> >>>>> I'm having problems with reproducing this issue. I thought I'd do a >>>>> quick test this evening but I proved to be wrong :-) >>>>> First I had to modify a bit the classes for a basic test to even >> start >>>>> working, to bypass JAXB complaints. >>>>> So here's what I have now. >>>>> testIt() results in >>>>> >>>>> {"ns1.definition": >> {"@repeating":"false","@index":"0","@name":"Credit >>>>> Line Increase Data", >>>>> >>>>> >> "ns1.structure":{"@repeating":"false","@index":"2","@name":"CreditLineIn >> cConversation", >>>>> "ns1.symbolic":[ >>>>> {"@index":"0","@name":"ReasonForIncrease"}, >>>>> {"@index":"4","@name":"TermConds"} >>>>> ] >>>>> } >>>>> } >>>>> } >>>>> >>>>> which is a simpler but a similar structure instance. >>>>> >>>>> @Test >>>>> public void testIt() throws Exception { >>>>> JSONProvider p = new JSONProvider(); >>>>> //p.setSerializeAsArray(true); >>>>> //p.setArrayKeys(Collections.singletonList("structure")); >>>>> >>>>> DataDefinition dd = new DataDefinition(); >>>>> dd.setName("Credit Line Increase Data"); >>>>> List<Field> fields = new ArrayList<Field>(); >>>>> Structure s = new Structure(); >>>>> s.setIndex(2); >>>>> s.setName("CreditLineIncConversation"); >>>>> List<Field> fields2 = new ArrayList<Field>(); >>>>> SymbolicField sf1 = new SymbolicField(); >>>>> sf1.setIndex(0); >>>>> fields2.add(sf1); >>>>> sf1.setName("ReasonForIncrease"); >>>>> SymbolicField sf2 = new SymbolicField(); >>>>> sf2.setIndex(4); >>>>> sf2.setName("TermConds"); >>>>> fields2.add(sf2); >>>>> s.setFields(fields2); >>>>> fields.add(s); >>>>> >>>>> dd.setFields(fields); >>>>> >>>>> ByteArrayOutputStream os = new ByteArrayOutputStream(); >>>>> >>>>> p.writeTo(dd, (Class)DataDefinition.class, >> DataDefinition.class, >>>>> DataDefinition.class.getAnnotations(), >>>>> MediaType.APPLICATION_JSON_TYPE, new >>>>> MetadataMap<String, Object>(), os); >>>>> >>>>> String str = os.toString(); >>>>> System.out.println(str); >>>>> } >>>>> >>>>> >>>>> readIt() tries to read this data : >>>>> >>>>> @Test >>>>> public void readIt() throws Exception { >>>>> String s = >>>>> >> "{\"ns1.definition\":{\"@repeating\":\"false\",\"@index\":\"0\",\"@name\ >> ":" >>>>> + "\"Credit Line Increase >>>>> >> Data\",\"ns1.structure\":{\"@repeating\":\"false\",\"@index\":\"2\"," >>>>> + >>>>> >> "\"@name\":\"CreditLineIncConversation\",\"ns1.symbolic\":[{\"@index\":\ >> "0\",\"@name\":" >>>>> + >>>>> >> "\"ReasonForIncrease\"},{\"@index\":\"4\",\"@name\":\"TermConds\"}]}}}"; >>>>> >>>>> JSONProvider p = new JSONProvider(); >>>>> Map<String, String> namespaceMap = new HashMap<String, >>>>> String>(); >>>>> namespaceMap.put("http://bla", "ns1"); >>>>> p.setNamespaceMap(namespaceMap); >>>>> byte[] bytes = s.getBytes(); >>>>> Object object = p.readFrom((Class)DataDefinition.class, >>>>> DataDefinition.class, >>>>> >>>>> DataDefinition.class.getAnnotations(), >>>>> null, null, new >>>>> ByteArrayInputStream(bytes)); >>>>> DataDefinition dd = (DataDefinition)object; >>>>> Field struct = >>>>> dd.getFieldsAsMap().get("CreditLineIncConversation"); >>>>> } >>>>> >>>>> but gets a ClassCastException at >>>>> DataDefinition dd = (DataDefinition)object; >>>>> >>>>> because it is a Structure object. >>>>> >>>>> and here're the slightly updated classes : >>>>> >>>>> >>>>> @XmlRootElement(name = "definition", namespace = "http://bla") >>>>> public static class DataDefinition extends Structure { >>>>> >>>>> } >>>>> >>>>> @XmlRootElement(name = "definition", namespace = "http://bla") >>>>> @XmlSeeAlso({DataDefinition.class, SymbolicField.class}) >>>>> >>>>> public static class Structure extends Field { >>>>> >>>>> @XmlAttribute(required = false) >>>>> boolean repeating = false; >>>>> >>>>> public boolean isRepeating() { >>>>> return repeating; >>>>> } >>>>> >>>>> @XmlElements( { @XmlElement(name = "structure", >>>>> namespace="http://bla", type = Structure.class), >>>>> @XmlElement(name = "numeric", >>>>> namespace="http://bla", type = NumericField.class), >>>>> @XmlElement(name = "symbolic", >>>>> namespace="http://bla", type = SymbolicField.class), >>>>> @XmlElement(name = "date", >> namespace="http://bla", >>>>> type = DateField.class), >>>>> @XmlElement(name = "boolean", >>>>> namespace="http://bla", type = BooleanField.class) }) >>>>> private List<Field> fields; >>>>> >>>>> // public List<Field> getFields() { >>>>> // return fields; >>>>> // } >>>>> >>>>> public void setFields(List<Field> fields) { >>>>> this.fields = fields; >>>>> } >>>>> >>>>> public Map<String, Field> getFieldsAsMap() { >>>>> Map<String, Field> fieldMap = new >> HashMap<String, >>>>> Field>(); >>>>> for (Field field : fields) { >>>>> fieldMap.put(field.name, field); >>>>> } >>>>> return fieldMap; >>>>> } >>>>> } >>>>> @XmlSeeAlso({DataDefinition.class, Structure.class}) >>>>> public static abstract class Field implements Serializable { >>>>> >>>>> @XmlAttribute >>>>> String name; >>>>> >>>>> // public String getName() { >>>>> // return name; >>>>> // } >>>>> >>>>> public void setName(String name) { >>>>> this.name = name; >>>>> } >>>>> >>>>> @XmlAttribute(required = false) >>>>> long index; >>>>> >>>>> // public long getIndex() { >>>>> // return index; >>>>> // } >>>>> // >>>>> public void setIndex(long index) { >>>>> this.index = index; >>>>> } >>>>> } >>>>> >>>>> @XmlRootElement(name = "symbolic", namespace = "http://bla") >>>>> public static class SymbolicField extends Field { >>>>> >>>>> } >>>>> >>>>> public static class NumericField extends Field { >>>>> >>>>> } >>>>> >>>>> public static class DateField extends Field { >>>>> >>>>> } >>>>> >>>>> public static class BooleanField extends Field { >>>>> >>>>> } >>>>> >>>>> >>>>> Please send me more info which can help me in reproducing it... >>>>> >>>>> Cheers, Sergey >>>>> >>>>> >>>>> mraible wrote: >>>>>> >>>>>> I'm facing an issue with CXF and JSON marshalling. My GET request >> for >>>>>> an object returns the following JSON. >>>>>> >>>>>> { >>>>>> "d.definition":{ >>>>>> "@filename":"credit-line-increase-data", >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"Credit Line Increase Data", >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"CreditLineIncConversation", >>>>>> "d.symbolic":[ >>>>>> { >>>>>> "@index":"0", >>>>>> "@name":"ReasonForIncrease" >>>>>> }, >>>>>> { >>>>>> "@index":"4", >>>>>> "@name":"TermsConds" >>>>>> } >>>>>> ], >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"AmountAppliedFor" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"AmountOffered" >>>>>> } >>>>>> ], >>>>>> "d.boolean":[ >>>>>> { >>>>>> "@index":"3", >>>>>> "@name":"CustApprovesCreditCheck" >>>>>> }, >>>>>> { >>>>>> "@index":"5", >>>>>> "@name":"CustAgreesToTermsConds" >>>>>> } >>>>>> ], >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"6", >>>>>> "@name":"CreditCheck", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"DateOfCreditCheck" >>>>>> }, >>>>>> "d.structure":{ >>>>>> "@repeating":"true", >>>>>> "@index":"1", >>>>>> "@name":"CreditLines", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"LineType" >>>>>> }, >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"Amount" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"DaysPastDue" >>>>>> } >>>>>> ] >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> >>>>>> The POST request sends something very similar back (ordering of >>>>>> elements shouldn't matter hopefully). >>>>>> >>>>>> { >>>>>> "d.definition":{ >>>>>> "@repeating":"false", >>>>>> "@filename":"credit-line-increase-data", >>>>>> "@index":"0", >>>>>> "@name":"Credit Line Increase Data", >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"CreditLineIncConversation", >>>>>> "d.symbolic":[ >>>>>> { >>>>>> "@index":"0", >>>>>> "@name":"ReasonForIncrease" >>>>>> }, >>>>>> { >>>>>> "@index":"4", >>>>>> "@name":"TermsConds" >>>>>> } >>>>>> ], >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"AmountAppliedFor" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"AmountOffered" >>>>>> } >>>>>> ], >>>>>> "d.boolean":[ >>>>>> { >>>>>> "@index":"3", >>>>>> "@name":"CustApprovesCreditCheck", >>>>>> "type":"BOOLEAN" >>>>>> }, >>>>>> { >>>>>> "@index":"5", >>>>>> "@name":"CustAgreesToTermsConds", >>>>>> "type":"BOOLEAN" >>>>>> } >>>>>> ], >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"6", >>>>>> "@name":"CreditCheck", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"DateOfCreditCheck" >>>>>> }, >>>>>> "d.structure":{ >>>>>> "@repeating":"true", >>>>>> "@index":"1", >>>>>> "@name":"CreditLines", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"LineType" >>>>>> }, >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"Amount" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"DaysPastDue" >>>>>> } >>>>>> ] >>>>>> } >>>>>> } >>>>>> }, >>>>>> "d.structure":{ >>>>>> "d.symbolic":[ >>>>>> { >>>>>> "@index":"0", >>>>>> "@name":"ReasonForIncrease" >>>>>> }, >>>>>> { >>>>>> "@index":"4", >>>>>> "@name":"TermsConds" >>>>>> } >>>>>> ], >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"CreditLineIncConversation", >>>>>> "d.boolean":[ >>>>>> { >>>>>> "@index":"3", >>>>>> "@name":"CustApprovesCreditCheck", >>>>>> "type":"BOOLEAN" >>>>>> }, >>>>>> { >>>>>> "@index":"5", >>>>>> "@name":"CustAgreesToTermsConds", >>>>>> "type":"BOOLEAN" >>>>>> } >>>>>> ], >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"AmountAppliedFor" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"AmountOffered" >>>>>> } >>>>>> ], >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"6", >>>>>> "@name":"CreditCheck", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"DateOfCreditCheck" >>>>>> }, >>>>>> "d.structure":{ >>>>>> "@repeating":"true", >>>>>> "@index":"1", >>>>>> "@name":"CreditLines", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"LineType" >>>>>> }, >>>>>> "d.numeric":[ >>>>>> { >>>>>> "@index":"1", >>>>>> "@name":"Amount" >>>>>> }, >>>>>> { >>>>>> "@index":"2", >>>>>> "@name":"DaysPastDue" >>>>>> } >>>>>> ] >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> >>>>>> The bug that I'm currently seeing is that the "symbolic", "boolean" >> and >>>>>> "numeric" arrays in the "CreditLineIncConversation" aren't getting >>>>>> converted from JSON to Java properly. In fact, they're completely >>>>>> dropped. Here's the resulting JSON after the save has been made: >>>>>> >>>>>> { >>>>>> "d.definition":{ >>>>>> "@filename":"credit-line-increase-data", >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"Credit Line Increase Data", >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"0", >>>>>> "@name":"CreditLineIncConversation", >>>>>> "d.structure":{ >>>>>> "@repeating":"false", >>>>>> "@index":"6", >>>>>> "@name":"CreditCheck", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"DateOfCreditCheck" >>>>>> }, >>>>>> "d.structure":{ >>>>>> "@repeating":"true", >>>>>> "@index":"1", >>>>>> "@name":"CreditLines", >>>>>> "d.symbolic":{ >>>>>> "@index":"0", >>>>>> "@name":"LineType" >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> } >>>>>> >>>>>> I tried looking at CXF's JAX-RS Documentation (specifically the >> json >>>>>> array serialization issues section) and making the following change >> in >>>>>> my configuration. >>>>>> >>>>>> @@ -45,8 +45,17 @@ >>>>>> <bean id="jsonProvider" >>>>>> class="org.apache.cxf.jaxrs.provider.JSONProvider"> >>>>>> <property name="namespaceMap" ref="jsonNamespaceMap"/> >>>>>> <property name="serializeAsArray" value="true"/> >>>>>> + <property name="arrayKeys" ref="jsonKeys"/> >>>>>> </bean> >>>>>> >>>>>> + <util:list id="jsonKeys"> >>>>>> + <value>structure</value> >>>>>> + <value>numeric</value> >>>>>> + <value>symbolic</value> >>>>>> + <value>date</value> >>>>>> + <value>boolean</value> >>>>>> + </util:list> >>>>>> + >>>>>> >>>>>> Unfortunately, this didn't work. >>>>>> >>>>>> The class that I'm trying to populate is defined as: >>>>>> >>>>>> @XmlRootElement(name = "definition") >>>>>> public class DataDefinition extends Structure { >>>>>> >>>>>> } >>>>>> >>>>>> It's parent (Structure), looks as follows: >>>>>> >>>>>> public class Structure extends Field { >>>>>> >>>>>> @XmlAttribute(required = false) >>>>>> boolean repeating = false; >>>>>> >>>>>> public boolean isRepeating() { >>>>>> return repeating; >>>>>> } >>>>>> >>>>>> @XmlElements( { @XmlElement(name = "structure", type = >>>>>> Structure.class), >>>>>> @XmlElement(name = "numeric", type = >> NumericField.class), >>>>>> @XmlElement(name = "symbolic", type = >> SymbolicField.class), >>>>>> @XmlElement(name = "date", type = DateField.class), >>>>>> @XmlElement(name = "boolean", type = BooleanField.class) >> }) >>>>>> private List<Field> fields; >>>>>> >>>>>> public List<Field> getFields() { >>>>>> return fields; >>>>>> } >>>>>> >>>>>> public void setFields(List<Field> fields) { >>>>>> this.fields = fields; >>>>>> } >>>>>> >>>>>> public Map<String, Field> getFieldsAsMap() { >>>>>> Map<String, Field> fieldMap = new HashMap<String, >> Field>(); >>>>>> for (Field field : getFields()) { >>>>>> fieldMap.put(field.getName(), field); >>>>>> } >>>>>> return fieldMap; >>>>>> } >>>>>> } >>>>>> >>>>>> I'd appreciate any pointers on what I need to do to make this work. >>>>>> >>>>>> Thanks! >>>>>> >>>>>> Matt >>>>>> >>>>> >>>>> >>>> >>>> >>> >>> >> >> -- >> View this message in context: >> http://www.nabble.com/Issues-marshalling-a-JSON-String-to-Java-Objects-% >> 28works-fine-from-Java-to-JSON%29-tp25531242p25775811.html >> Sent from the cxf-user mailing list archive at Nabble.com. >> >> >> > > -- View this message in context: http://www.nabble.com/Issues-marshalling-a-JSON-String-to-Java-Objects-%28works-fine-from-Java-to-JSON%29-tp25531242p25827165.html Sent from the cxf-user mailing list archive at Nabble.com.
