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/09/23 20:37:35 UTC

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

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-tp25531242p25531242.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.


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

Posted by mraible <ma...@raibledesigns.com>.
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: HELP! Was:RE: Accessing JAX-RS MessageContext in a filter

Posted by "Pydipati, Karuna" <kp...@stubhub.com>.
 
I sent this mail to my team sometime back. Hope, this may be helpful. I
am using it in Impl class. Not in filter.

================
In the REST world, in order to get/set Cookie information or any other
information that is stored in httpRequest, here is the simple and
elegant way. 
 
1. DO NOT add anything in web service interface. Not even in method
signature (Common mistake is that developers try to add arguments to get
Cookie information)
2. Have a filed MessageContext in Impl class and annotate it with
@Context
3. Try to access it in any method. This is thread safe interface because
it implements ThreadLocalMessageContext
4. You can access all the below mentioned information from
MessageContext
    UriInfo, 
    SecurityContext, 
    HttpHeaders, 
    Providers, 
    Request, 
    ContextResolver, 
    Servlet types (HttpServletRequest, HttpServletResponse,
ServletContext, ServletConfig)
 
 
 
Here is example for usage of MessageContext
 
public class SomeWebServiceImpl implements SomeWebServiceService {

    @Context
    MessageContext resp;
 
    public SomeApiResponse someMethod(SomeRequest someRequest) {
        AuthenticatedSession authenticatedSession = null;
        SomeApiResponse someApiResponse = new SomeApiResponse();
        try {
        
            HttpServletResponse httpServletResponse =
resp.getHttpServletResponse().addCookie(STUB_SESS);
            
            HttpHeaders httpheaders = resp.getHttpHeaders();
            
            HttpServletRequest httpServletRequest =
resp.getHttpServletRequest();
            
            ServletConfig servletConfig = resp.getServletConfig();
            
            ServletContext servletContext = resp.getServletContext();
            
            UriInfo uriInfo = resp.getUriInfo();
            
            Providers providers = resp.getProviders();
            
        } catch ( Exception e) {
            log.error(" Exception: " + e);
        }
 
        return someApiResponses;
 
    }
 
 
 
public interface SomeWebServiceService {
 
 @Path("identified")
 @POST
 public  SomeApiResponse someMethod(SomeRequest someRequest);
 
}
====================

Regards
Karuna Pydipati
StubHub/eBay - Platform & Services
Phone: (415)222-8752
Email: kpydipati@ebay.com

 


-----Original Message-----
From: Sadhana Jain [mailto:Sadhana.Jain@rovicorp.com] 
Sent: Tuesday, September 29, 2009 12:55 AM
To: users@cxf.apache.org
Cc: Sergey Beryozkin
Subject: HELP! Was:RE: Accessing JAX-RS MessageContext in a filter

 
Hi cxf group,

Could you please respond to my question below? The main question is if
Context get/set is allowed in JAX-RS filters?
I need an answer urgently as I need to deliver some code by tomorrow And
I need to figure out whether to implement a work around or there is
Something simple I am missing and have overlooked in using JAX-RS CXF?

Thanks very much for your help in the past. Hope to hear from Someone
soon.

Sadhana


-----Original Message-----
From: Sadhana Jain [mailto:Sadhana.Jain@rovicorp.com]
Sent: Monday, September 28, 2009 10:53 AM
To: users@cxf.apache.org
Subject: Accessing JAX-RS MessageContext in a filter

 
Hi All,

I am trying to get access to MessageContext in a filter (that implements
RequestHandler interface) by doing this:

private MessageContext mc; 

@Context
public void setMessageContext(MessageContext msgC) {
  mc=msgC;
}

Because I saw in the list that a bug was filed about if @Context was
used on a fields like this:
@Context
private MessageContext mc; 

But even using Context on the setter does not work. Do I need to do any
wiring in the Spring file when I use the Setter like above?

Is @Context suppose to work with filters ( I thought they should as
filters are like providers)?

What I am trying to do using Context is set a Map that I created in the
filter after processing http headers And I want to access that Map in
some other class later in the code and would like to use @Context to get
the map.
Is this a good use of @Context? Or can I do this in any other way?

Thanks a lot for any help.
Sadhana

Sadhana Jain
Sr. Software Engineer


Rovi Corporation
795 Folsom St, Suite 200
San Francisco, CA 94107
Direct: 415.247.5023 | Mobile: 925.212.6495 sadhana.jain@rovicorp.com
rovicorp.com


Rovi. The new name for Macrovision.



Re: HELP! Was:RE: Accessing JAX-RS MessageContext in a filter

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Sadhana

Unfortunatley, it will only be possible to inject contexts in filters starting from 2.2.4.
However, as a workaround, you can get most of what you can get from a MessageContext using a provided Message instance
here's some examples :

HttpServletRequest request = (HttpServletRequest)message.get(AbstractHttpDestination.HTTP_REQUEST)
HttpHeaders headers = new HttpHeadersImpl(message);
UriInfo ui = new UriInfoImpl(m, null);
// etc...

let me know please if you need more info,
cheers, Sergey


----- Original Message ----- 
From: "Sadhana Jain" <Sa...@rovicorp.com>
To: <us...@cxf.apache.org>
Cc: "Sergey Beryozkin" <sb...@progress.com>
Sent: Tuesday, September 29, 2009 8:54 AM
Subject: HELP! Was:RE: Accessing JAX-RS MessageContext in a filter



Hi cxf group,

Could you please respond to my question below? The main
question is if Context get/set is allowed in JAX-RS filters?
I need an answer urgently as I need to deliver some code by tomorrow
And I need to figure out whether to implement a work around or there is
Something simple I am missing and have overlooked in using JAX-RS CXF?

Thanks very much for your help in the past. Hope to hear from
Someone soon.

Sadhana


-----Original Message-----
From: Sadhana Jain [mailto:Sadhana.Jain@rovicorp.com]
Sent: Monday, September 28, 2009 10:53 AM
To: users@cxf.apache.org
Subject: Accessing JAX-RS MessageContext in a filter


Hi All,

I am trying to get access to MessageContext in a filter (that implements RequestHandler interface) by doing this:

private MessageContext mc;

@Context
public void setMessageContext(MessageContext msgC) {
  mc=msgC;
}

Because I saw in the list that a bug was filed about if @Context was used on a fields like this:
@Context
private MessageContext mc;

But even using Context on the setter does not work. Do I need to do any wiring in the Spring file when I use the Setter like above?

Is @Context suppose to work with filters ( I thought they should as filters are like providers)?

What I am trying to do using Context is set a Map that I created in the filter after processing http headers And I want to access 
that Map in some other class later in the code and would like to use @Context to get the map.
Is this a good use of @Context? Or can I do this in any other way?

Thanks a lot for any help.
Sadhana

Sadhana Jain
Sr. Software Engineer


Rovi Corporation
795 Folsom St, Suite 200
San Francisco, CA 94107
Direct: 415.247.5023 | Mobile: 925.212.6495 sadhana.jain@rovicorp.com rovicorp.com


Rovi. The new name for Macrovision.



HELP! Was:RE: Accessing JAX-RS MessageContext in a filter

Posted by Sadhana Jain <Sa...@rovicorp.com>.
 
Hi cxf group,

Could you please respond to my question below? The main
question is if Context get/set is allowed in JAX-RS filters?
I need an answer urgently as I need to deliver some code by tomorrow
And I need to figure out whether to implement a work around or there is
Something simple I am missing and have overlooked in using JAX-RS CXF?

Thanks very much for your help in the past. Hope to hear from
Someone soon.

Sadhana


-----Original Message-----
From: Sadhana Jain [mailto:Sadhana.Jain@rovicorp.com] 
Sent: Monday, September 28, 2009 10:53 AM
To: users@cxf.apache.org
Subject: Accessing JAX-RS MessageContext in a filter

 
Hi All,

I am trying to get access to MessageContext in a filter (that implements RequestHandler interface) by doing this:

private MessageContext mc; 

@Context
public void setMessageContext(MessageContext msgC) {
  mc=msgC;
}

Because I saw in the list that a bug was filed about if @Context was used on a fields like this:
@Context
private MessageContext mc; 

But even using Context on the setter does not work. Do I need to do any wiring in the Spring file when I use the Setter like above?

Is @Context suppose to work with filters ( I thought they should as filters are like providers)?

What I am trying to do using Context is set a Map that I created in the filter after processing http headers And I want to access that Map in some other class later in the code and would like to use @Context to get the map.
Is this a good use of @Context? Or can I do this in any other way?

Thanks a lot for any help.
Sadhana

Sadhana Jain
Sr. Software Engineer


Rovi Corporation
795 Folsom St, Suite 200
San Francisco, CA 94107
Direct: 415.247.5023 | Mobile: 925.212.6495 sadhana.jain@rovicorp.com rovicorp.com


Rovi. The new name for Macrovision.



Accessing JAX-RS MessageContext in a filter

Posted by Sadhana Jain <Sa...@rovicorp.com>.
 
Hi All,

I am trying to get access to MessageContext in a filter (that implements RequestHandler interface)
by doing this:

private MessageContext mc; 

@Context
public void setMessageContext(MessageContext msgC) {
  mc=msgC;  
}

Because I saw in the list that a bug was filed about if @Context was used on a fields like this:
@Context
private MessageContext mc; 

But even using Context on the setter does not work. Do I need to do any wiring in the Spring file when I use the
Setter like above?

Is @Context suppose to work with filters ( I thought they should as filters are like providers)?

What I am trying to do using Context is set a Map that I created in the filter after processing http headers
And I want to access that Map in some other class later in the code and would like to use @Context to get the map.
Is this a good use of @Context? Or can I do this in any other way?

Thanks a lot for any help.
Sadhana

Sadhana Jain
Sr. Software Engineer


Rovi Corporation
795 Folsom St, Suite 200
San Francisco, CA 94107
Direct: 415.247.5023 | Mobile: 925.212.6495
sadhana.jain@rovicorp.com
rovicorp.com


Rovi. The new name for Macrovision.



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

Posted by Sergey Beryozkin <se...@iona.com>.
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-tp25531242p25649683.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>.
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-tp25531242p25636080.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

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