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":"CreditLineIncConversation", > "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/resources/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":"CreditLineIncConversation", >>> "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.
