Use class name as root key for JSON Jackson serialization

前端 未结 11 2700
长情又很酷
长情又很酷 2020-11-27 18:05

Suppose I have a pojo:

import org.codehaus.jackson.map.*;

public class MyPojo {
    int id;
    public int getId()
    { return this.id; }

    public void          


        
相关标签:
11条回答
  • 2020-11-27 18:19

    I would be interested in hearing the OP's solution for this. I'm having similar issues where my RESTful web service is serializing objects as either XML or JSON for clients. The Javascript clients need to know the wrapping type so that can parse it. Coupling the type to a URI pattern is not an option.

    Thanks.

    Edit: I noticed that Spring MappingJacksonJsonMarshaller adds the wrapping class when marshalling, so I stepped through the code in debug and noticed that Spring passes in a HashMap with a single key-value pair such that the key is the wrapping name and the value is the object. So, I extended JacksonJaxbJsonProvider, override the writeTo() method and added the following:

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put(value.getClass().getSimpleName(), value);
    super.writeTo(map, type, genericType, annotations, mediaType, httpHeaders,entityStream);
    

    It's a bit of a hack, but it works nicely.

    0 讨论(0)
  • 2020-11-27 18:19

    I have found through experience that it is a good idea for all JSON to include both the backend type (as a string) and the component type used to render it in the front end (if using something like angular or Vue).

    The justification for doing this is so that you can process various types with a single set of code.

    In vue, for example, having the name of the UI component in the data allows you, among other things, to have a screen rendering a list of children of different types using only a single tag in the parent template.

      <component :is="child.componentType"/>.
    

    For backend systems and web services - I prefer to use a single web service processor class that provides logging, auditing and exception handling for all web services by looking up the appropriate processor class based on the incoming payload. That makes the implementation of all my web services look exactly the same (about 3 lines of code), and I get detailed event logging through the lifecycle of the call without writing any per service code to do so.

    Having the type wrapping the JSON makes it self documenting. If all you see are the properties, you have no idea what you are looking at until you find the corresponding end point.

    If you want to write data driven software, being able to identify what you are processing is a basic requirement.

    0 讨论(0)
  • 2020-11-27 18:25

    there is another way i used and that worked for me. I am working with a third party jar, so i have no control for annotations. So i had to write through bit of hack.

    Override: org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(SerializationConfig, BasicBeanDescription)

    Add your property as below

    List<BeanPropertyWriter> props = super.findBeanProperties(config, beanDesc);
    BeanPropertyWriter bpw = null;
    try {
         Class cc = beanDesc.getType().getRawClass();
         Method m = cc.getMethod("getClass", null);
         bpw = new BeanPropertyWriter("$className", null, null, m, null,true, null);
    } catch (SecurityException e) {
      // TODO
    } catch (NoSuchMethodException e) {
      // TODO
    }
    props.add(bpw);
    return props;
    

    This way i get more control and can do other kind of filters too.

    0 讨论(0)
  • 2020-11-27 18:29

    use withRootName.

    objectMapper.writer().withRootName(MyPojo.class.getName());
    
    0 讨论(0)
  • 2020-11-27 18:30

    There is also a nice annotation for this:

    @JsonRootName(value = "my_pojo")
    public class MyPojo{
      ...
    }
    

    will generate:

    {
      "my_pojo" : {...}
    }
    
    0 讨论(0)
  • 2020-11-27 18:30
    @JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME) 
    

    This annotation works perfectly, as suggested by Arun Prakash. I was trying to get json in this form:

    {"Rowset":{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}
    

    but getting like this:

    {"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}
    

    Now that annotation resolved my problem.

    0 讨论(0)
提交回复
热议问题