2012-01-19 20 views
8

BuJackson: nokta gösterimi ile iç içe nesnesi 'JSON özelliği dönüştürme

{ "id":1, "name":"Jack", "parent.id":2 } 

Not gibi "parent.id" özelliği

üzerinde nokta bir JSON bu o JSON haritaya mümkün mü var aşağıdaki sınıflara?

class Child { 
    private int id; 
    private String name; 

    private Parent parent; 

    //getter and setter methods 
} 

class Parent { 
    private int id; 
    private String name; 

    //getter and setter methods 
} 

Yani haritalama sonucu aşağıdaki açıklamalara benzer olacaktır:

Parent parent = new Parent(); 
parent.setId(2); 

Child child = new Child(); 
child.setId(1); 
child.setName("Jack"); 
child.setParent(parent); // Here is the result 
+0

Kendi MessageBodyReader tanımlayarak yapabilirsiniz :) yardımcı olur, ama sormak zorunda

@RequestMapping("/saveChild.json") @ResponseBody public Child saveChild(@RequestBody Child child) { // do something with child return child; } 

Umut kullanabilirsiniz ... neden ? – Perception

+0

Çünkü ExtJS kullanıyorum ve yukarıdaki gibi bir format ile JSON yolladı. –

+2

Tüm çözümlerimizde Ext.js istemciler var. Modellerini düzeltmek için GUI dev'ini edinin. – Perception

cevap

12

bu

{ "id":1, "name":"Jack", "parent": { "id":2 } } 

içine bu

{ "id":1, "name":"Jack", "parent.id":2 } 

dönüştürebilirsiniz bu

kullanarak
// I'm using jQuery here 
$.fn.serializeObject = function() { 
    var arrayData, objectData; 
    arrayData = this.serializeArray(); 
    objectData = {}; 

    $.each(arrayData, function() { 
    var value; 

    if (this.value != null) { 
     value = this.value; 
    } else { 
     value = ''; 
    } 

    // search for "parent.id" like attribute 
    if (this.name.indexOf('.') != -1) { 
     var attrs = this.name.split('.'); 
     var tx = objectData; 

     for (var i = 0; i < attrs.length - 1; i++) { 
     if (objectData[attrs[i]] == undefined) 
      objectData[attrs[i]] = {}; 
     tx = objectData[attrs[i]]; 
     } 
     tx[attrs[attrs.length - 1]] = value; 
    } else { 
     if (objectData[this.name] != null) { 
     if (!objectData[this.name].push) { 
      objectData[this.name] = [objectData[this.name]]; 
     } 

     objectData[this.name].push(value); 
     } else { 
     objectData[this.name] = value; 
     } 
    } 
    }); 

    return objectData; 
}; 

ve sonra JSON.serialize() kullanarak kodunuzu seri hale getirebilirsiniz.

1. modül

2. JSON Kendinizi ayrıştırmak özel Jackson serisini oluşturmak: Eğer Jackson kullanıyorsanız

, o zaman bunlardan birini yaparak JSON istek dizesini serisini

public Child parseJackson(String jsonRequest) { 
    // what we need 
    ObjectMapper mapper; 
    JsonNode root, parentNode; 

    // your models 
    Child child; 
    Parent parent; 

    // assign 
    mapper = new ObjectMapper(); 
    root = mapper.readTree(jsonRequest); // deserialize JSON as tree 
    parentNode = root.get("parent"); // get the "parent" branch 

    // assign (again) 
    child = mapper.readValue(root, Child.class); 
    parent = mapper.readValue(parentNode, Parent.class); 

    child.setParent(parent); 

    return child; 
} 

Bu yöntemin dezavantajı iç içe geçmiş nesnelerle her JsonRequest için ayrıştırmak zorunda olduğunu ve zaman inci dağınık olacak Karmaşık iç içe bir yapıdır. bu bir sorun ise, ben bu sürecini fikri jenerik sürecini oluşturmaktır

otomatik hale getirmek için özel bir Jackson ObjectMapper sınıfı oluşturmak # 3

3. yapmanızı öneririm böylece kalkabileceğini 2. için iç içe geçmiş herhangi bir istek.

public class CustomObjectMapper extends ObjectMapper { 

    // here's the method you need 
    @Override 
    public <T> T readValue(String src, Class<T> type) 
     throws IOException, JsonParseException, JsonMappingException { 

    JsonNode root = this.readTree(src); 
    try { 
     return readNestedValue(root, type); 
    } catch (InstantiationException | IllegalAccessException | IOException 
     | IllegalArgumentException | InvocationTargetException e) { 
     return super.readValue(src, type); 
    } 

    } 

    // if you're using Spring, I suggest you implement this method as well 
    // since Spring's MappingJacksonHttpMessageConverter class will call 
    // this method. 
    @Override 
    public <T> T readValue(InputStream src, JavaType type) 
     throws IOException, JsonParseException, JsonMappingException { 

    JsonNode root = this.readTree(src); 
    try { 
     return readNestedValue(root, (Class<T>) type.getRawClass()); 
    } catch (InstantiationException | IllegalAccessException | IOException 
     | IllegalArgumentException | InvocationTargetException e) { 
     return super.readValue(src, type); 
    } 

    } 

    // we need this to recursively scan the tree node 
    protected <T> T readNestedValue(JsonNode root, Class<T> type) 
     throws InstantiationException, IllegalAccessException, IOException, 
     IllegalArgumentException, InvocationTargetException { 

    // initialize the object use ObjectMapper's readValue 
    T obj = super.readValue(root, type); 
    Iterator it = root.getFieldNames(); 
    while (it.hasNext()) { 
     String name = (String) it.next(); 
     String camelCaseName = name.substring(0, 1).toUpperCase() + name.substring(1); 
     JsonNode node = root.get(name); 

     Field f; 
     try { 
     f = type.getDeclaredField(name); 
     } catch (NoSuchFieldException e) { 
     f = findFieldInSuperClass(name, type.getSuperclass()); 
     } 
     // if no field found then ignore 
     if (f == null) continue; 

     Method getter, setter; 
     try { 
     getter = type.getMethod("get" + camelCaseName); 
     } catch (NoSuchMethodException e) { 
     getter = findGetterInSuperClass("get" + camelCaseName, type.getSuperclass()); 
     } 
     // if no getter found or it has been assigned then ignore 
     if (getter == null || getter.invoke(obj) != null) continue; 

     try { 
     setter = type.getMethod("set" + camelCaseName); 
     } catch (NoSuchMethodException ex) { 
     setter = findSetterInSuperClass("set" + camelCaseName, type.getSuperclass(), f.getType()); 
     } 
     // if no setter found then ignore 
     if (setter == null) continue; 

     setter.invoke(obj, readNestedValue(node, f.getType())); 
    } 

    return obj; 
    } 

    // we need this to search for field in super class 
    // since type.getDeclaredField() will only return fields that in the class 
    // but not super class 
    protected Field findFieldInSuperClass(String name, Class sClass) { 
    if (sClass == null) return null; 
    try { 
     Field f = sClass.getDeclaredField(name); 
     return f; 
    } catch (NoSuchFieldException e) { 
     return findFieldInSuperClass(name, sClass.getSuperclass()); 
    } 
    } 

    protected Method findGetterInSuperClass(String name, Class sClass) { 
    if (sClass == null) return null; 
    try { 
     Method m = sClass.getMethod(name); 
     return m; 
    } catch (NoSuchMethodException e) { 
     return findGetterInSuperClass(name, sClass.getSuperclass()); 
    } 
    } 

    protected Method findSetterInSuperClass(String name, Class sClass, Class type) { 
    if (sClass == null) return null; 
    try { 
     Method m = sClass.getMethod(name, type); 
     return m; 
    } catch (NoSuchMethodException e) { 
     return findSetterInSuperClass(name, sClass.getSuperclass(), type); 
    } 
    } 
} 

İlkbahar kullanıyorsanız, son adım bu sınıfı Spring Bean olarak kaydettirmektir. kurmak Bunlarla

<mvc:annotation-driven> 
    <mvc:message-converters> 
     <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> 
     <property name="objectMapper"> 
      <bean class="x.y.z.CustomObjectMapper"/> 
     </property> 
     </bean> 
    </mvc:message-converters> 
    </mvc:annotation-driven> 

kolayca bu

İlgili konular