Parse Json array init single object in Spring boot

2019-08-19 09:44发布

问题:

All I need some help to parse the object on the class base. I have a list of Imp object. i don't want it map all to the class and create the all object. I need only the First object of the Imp in my RtbRequest class.

Reason:- why i need to do like that. In imp json user send the non-number of imp object's in list and required on one object. i'd want to parse all. Is this possible

My Pojo Class

@JsonInclude(JsonInclude.Include.NON_NULL)
public class RtbRequest {

   // number of attribute
    private Imp imp;

    public void setImp(Imp imp) {
        this.imp = imp;
    }

}
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Imp {

   // number of attribute
   @JsonIgnore
   private Map<String, String> impMap = new HashMap<>();
   private String id;
   private Double bidfloor;
    //final-map
    public void setId(String id) {
        log.info("set--id--rtb--Imp");
        this.id = id;
        impMap.put("impid", getId());
    }


}

My Json Object

{
    "id": "ded06290-f586-45c6-bbcb-015adba03e39",
    "imp": [{
            "id": "1",
            "video": {
                "linearity": 1,
                "maxduration": 120,
                "protocols": [2, 5, 3, 6],
                "w": 1280,
                "h": 720,
                "startdelay": 0,
                "skip": 1,
                "sequence": 1,
                "playbackmethod": [1, 2, 3],
                "api": [2]
            },
            "bidfloor": 0.0,
            "secure": 1

        },
        {
            "id": "2",
            "video": {
                "linearity": 1,
                "maxduration": 120,
                "protocols": [2, 5, 3, 6],
                "w": 1280,
                "h": 720,
                "startdelay": 0,
                "skip": 1,
                "sequence": 1,
                "playbackmethod": [1, 2, 3],
                "api": [2]
            },
            "bidfloor": 0.0,
            "secure": 1
        }
    ]

}

My RestController

@RequestMapping(value= { "/request/{partner}"}, method = RequestMethod.POST)
public Map<String, String> getRtbResponse(@PathVariable String partner, @RequestBody RtbRequest request) {}

回答1:

JSON serialization works best if you serialize into strong types, so each JSON object will normally map directly to a Java class. If all your items look like:

{
    "id": "1",
    "exp": 3600,
    "secure": 0,
    "instl": 1
}

you should create an identical Java class, with getters and setters

Class Item {
    String id;
    long exp;
    int secure;
    int instl;
    // setters and getter
}

The controller method signature should be:

 @RequestMapping(value= { "/request/{partner}"}, method = 
 RequestMethod.POST)
public Map<String, String> getRtbResponse(@RequestBody List<Item> data, @PathVariable String partner) {}

If each partner sends in data in different formats, the solution may depend on weather you need to process the data, or simply store it. If you 'just' need to store the data and not process it, you can use the fact that all JSON object can be handled as maps, so it is possible to make your controller like this:

 @RequestMapping(value= { "/request/{partner}"}, method = 
 RequestMethod.POST)
public Map<String, String>> getRtbResponse(@RequestBody List<Map<String, Object>> data, @PathVariable String partner) {}

However if you need to process the data in any way, using Map<String, Object> is generally not a good plan.

In Java we could create an Interface PartnerItem and multiple subclasses, each matching the data submitted by each partner. This is also possible in JSON, but since JSON objects have no name, it needs to be included in some other way. Here is a link to a guide that explains how Jackson inheritance works

Note: Personally I never use array as my top level JSON structure when I design APIs, I always use object. The reason is that I can add additional fields to an object, which allows me to mutate the API in a backwards compatible way - this is not possible if your top-level structure is an array.



回答2:

All Sorry for late replay for this issue i handle this by use of Cross filter. I first update my IMP list to Object after that i update the ReadHttpServletRequest stream by adding this Request into do-filer change.

Main Key Point

Note:- final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getNewRequest().getBytes());

@Component
public class Cross implements Filter {

    private final static Logger log = LoggerFactory.getLogger(Cross.class);

    //********************************
    //           Filter Config      //
    //********************************
    private static Integer count = 0;
    private Long before;


    @Autowired
    ValidatorService validatorService;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {

        try {

            // response
            log.info("=================Request-Start-"+(count++)+"-=====================");
            before = System.currentTimeMillis();
            ReadHttpServletRequest requestWrapper = new ReadHttpServletRequest((HttpServletRequest) servletRequest);

            HttpServletResponse response = (HttpServletResponse) servletResponse;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "X-requested-with, Content-Type");

            String body = requestWrapper.getNewRequest();
            String header = requestWrapper.getHeader();
            if (body != null && header != null) {
                /*
                * Note:- This below line's first update the request and conver the imp's to imp by getting
                * the single first index object. if the object is not their this will not process ad send the simple same
                * json string for validation if the string valid then dofilter map the json into @Pojo.
                * */
                log.info("New:- "+"header " + header + ", body " + body);
                if (validatorService.isResponseValidator(body, InputType.REQUEST.toString().equals("REQUEST") ? InputType.REQUEST : null)) {
                    filterChain.doFilter(requestWrapper, servletResponse);
                } else {
                    /*
                    * Note:- IF Validator fail this will show error
                    * if imp's size 0 then here
                    * if imp's object not their then here
                    * */
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    String responseMessage = "{\"result\": \"Oops an error happened!\nSomething bad happened uh-oh!\"}";
                    response.getWriter().print(responseMessage);
                }
            }
        }catch (NullPointerException e) {
            log.error("--Error--> "+ e.getMessage());
            filterChain.doFilter(servletRequest, servletResponse);

        }finally {
            long result = System.currentTimeMillis() - before;
            log.info("Total response time -> (" + (result) + ") miliseconds");
            log.info("=================Request-End=====================");
        }
    }

    @Override
    public void destroy() { }

}


public class ReadHttpServletRequest extends HttpServletRequestWrapper {

    private final static Logger log = LoggerFactory.getLogger(Cross.class);

    private String body = "";
    private String newBody = "";
    private String header = "";
    private final String IMP = "imp";

    public ReadHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        BufferedReader bufferedReader = request.getReader();
        String line;
        StringBuffer stringBuffer = new StringBuffer();
        while ((line = bufferedReader.readLine()) != null) {
            stringBuffer.append(line);
        }
        setBody(stringBuffer.toString());
        // fetch header
        this.setHeader(request.getHeader("x-openrtb-version"));
        log.info("Old:- "+"header " + getHeader() + ", body " + getBody());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream =
                new ByteArrayInputStream(getNewRequest().getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
            @Override
            public boolean isFinished() { return false; }
            @Override
            public boolean isReady() { return false; }
            @Override
            public void setReadListener(ReadListener listener) {}

        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public void setBody(String body) {
        log.info("Body-set");
        this.body = body;
        // set the new body also
        setNewRequest(getUpdateRequestBody(getBody()));
    }
    public void setHeader(String header) {
        log.info("Header-set");
        this.header = header;
    }

    public String getBody() {
        log.info("Body-get");
        return this.body;
    }
    public String getHeader() {
        log.info("Header-get");
        return this.header;
    }

    private String getUpdateRequestBody(String body) {

        JSONObject jsonRequest = (JSONObject) JSONSerializer.toJSON(body);
        /**
         * Find the imp's list and convert into the json-object then add into the request as update's
         * */
        if(jsonRequest.get(IMP) != null) {
            JSONArray jsonArray = jsonRequest.getJSONArray(IMP);
            if(jsonArray != null && (jsonArray.isArray() && jsonArray.size() > 0)) {
                JSONObject impObject = jsonRequest.getJSONArray(IMP).getJSONObject(0);
                // remove the list of imp
                jsonRequest.remove(IMP);
                // add the new one into the json reqeust
                jsonRequest.put(IMP, impObject);
            }
        }
        return jsonRequest.toString();
    }

    private void setNewRequest(String body) {
        log.info("newBody set");
        this.newBody = body;
    }

    public String getNewRequest() {
        log.info("newBody get");
        return this.newBody;
    }
}