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.

Reply via email to