Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>you can convert this</p> <pre class="lang-js prettyprint-override"><code>{ "id":1, "name":"Jack", "parent.id":2 } </code></pre> <p>into this</p> <pre class="lang-js prettyprint-override"><code>{ "id":1, "name":"Jack", "parent": { "id":2 } } </code></pre> <p>by using this</p> <pre class="lang-js prettyprint-override"><code>// 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 &lt; 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; }; </code></pre> <p>and then you can serialize your code by using <code>JSON.serialize()</code>.</p> <p>if you are using Jackson, then you can deserialize the JSON request string by doing any of these:</p> <p><strong>1. create a custom Jackson deserialize module</strong></p> <p><strong>2. parse the JSON yourself</strong></p> <pre class="lang-java prettyprint-override"><code>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; } </code></pre> <p>the downside of this method is you have to parse for every single JsonRequest with nested objects and it will be messy when there's a complex nested structure. If this is a problem, I suggest you do the #3</p> <p><strong>3. create a custom Jackson ObjectMapper class to automate this process</strong></p> <p>The idea is to build generic process for #2 so that it could handle any nested request.</p> <pre><code>public class CustomObjectMapper extends ObjectMapper { // here's the method you need @Override public &lt;T&gt; T readValue(String src, Class&lt;T&gt; 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 &lt;T&gt; T readValue(InputStream src, JavaType type) throws IOException, JsonParseException, JsonMappingException { JsonNode root = this.readTree(src); try { return readNestedValue(root, (Class&lt;T&gt;) type.getRawClass()); } catch (InstantiationException | IllegalAccessException | IOException | IllegalArgumentException | InvocationTargetException e) { return super.readValue(src, type); } } // we need this to recursively scan the tree node protected &lt;T&gt; T readNestedValue(JsonNode root, Class&lt;T&gt; 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); } } } </code></pre> <p>If you're using Spring, then the final step is registering this class as Spring bean.</p> <pre class="lang-xml prettyprint-override"><code>&lt;mvc:annotation-driven&gt; &lt;mvc:message-converters&gt; &lt;bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"&gt; &lt;property name="objectMapper"&gt; &lt;bean class="x.y.z.CustomObjectMapper"/&gt; &lt;/property&gt; &lt;/bean&gt; &lt;/mvc:message-converters&gt; &lt;/mvc:annotation-driven&gt; </code></pre> <p>with these set up you can easily use </p> <pre><code>@RequestMapping("/saveChild.json") @ResponseBody public Child saveChild(@RequestBody Child child) { // do something with child return child; } </code></pre> <p>Hope this helps :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload