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-tp25531242p25825764.html Sent from the cxf-user mailing list archive at Nabble.com.
