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.

Reply via email to