You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by mraible <ma...@raibledesigns.com> on 2009/10/06 22:14:25 UTC

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":"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.


RE: Issues marshalling a JSON String to Java Objects (works fine from Java to JSON)

Posted by Sergey Beryozkin <se...@iona.com>.
> I'm working in background on making sure one can do pretty much any sort of
transformation (well, most simple enough transformations :-)) 

Finally I've committed some initial support for it.
It should be possible to easily :

- drop elements, namespaces, attributes
- change names, namespaces
- append elements
- require attributes be serialized as elements, etc...
on the in/out

I'll be working on updating the docs later on
Sergey  


Sergey Beryozkin wrote:
> 
> 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:matt@raibledesigns.com] 
>>> Sent: 06 October 2009 21:14
>>> To: users@cxf.apache.org
>>> 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://old.nabble.com/Issues-marshalling-a-JSON-String-to-Java-Objects-%28works-fine-from-Java-to-JSON%29-tp25531242p26256808.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: Issues marshalling a JSON String to Java Objects (works fine from Java to JSON)

Posted by Sergey Beryozkin <se...@iona.com>.
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:matt@raibledesigns.com] 
>> Sent: 06 October 2009 21:14
>> To: users@cxf.apache.org
>> 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.


RE: Issues marshalling a JSON String to Java Objects (works fine from Java to JSON)

Posted by mraible <ma...@raibledesigns.com>.
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:matt@raibledesigns.com] 
> Sent: 06 October 2009 21:14
> To: users@cxf.apache.org
> 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.


RE: Issues marshalling a JSON String to Java Objects (works fine from Java to JSON)

Posted by Sergey Beryozkin <sb...@progress.com>.
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:matt@raibledesigns.com] 
Sent: 06 October 2009 21:14
To: users@cxf.apache.org
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.