1

I am trying to receive a JSON object in @RequestBody which is not known to me i.e. the JSON Object could be of any length and data.

Let's say, JSON could be as shown below

{'seqNo': 10 }

{'country': 'US', 'state': 'CA'}

{'customer': 'Alex', product: 'UPS', date:'25-Mar-2018'}

And In Spring Boot Api, I have a method to receive that JSON Object.

@PostMapping(value = "/lookup")
public ResponseEntity<AppResponse> getLookup(@RequestBody LookupRequestObject lookupRequestObject) {

        // THIS METHOD KNOWS WHICH FIELD TO USE
        // FURTHER LOGIC WOULD BE HERE.


        return ResponseEntity.ok(response);

    }

I have read about Jackson Serialization but still finding solution for this.

Customize the Jackson ObjectMapper

Any help would be much appreciated.

2
  • You may accept the request body as a String , then use Jackson by yourself to deserialize the string to the relevant class. Commented Apr 2, 2019 at 6:52
  • @Arnaud, the relevant class means each JSON (shown above) has relevant class. Commented Apr 2, 2019 at 6:55

3 Answers 3

6

You could just use a map for your input. Then you can access filed in the map depending on what kind of fields it contains.

@PostMapping(value = "/lookup")
public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> lookupRequestObject) {

    // THIS METHOD KNOWS WHICH FIELD TO USE
    // FURTHER LOGIC WOULD BE HERE.

    return ResponseEntity.ok(response);
}
Sign up to request clarification or add additional context in comments.

Comments

4

If JSON object structure is not known, you can always use Map<String, Object> type and convert it to POJO or directly work on Map. In case you need POJO you can use convertValue method:

@PostMapping(value = "/lookup")
public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> payload) {
    // read map
    ObjectMapper objectMapper = new ObjectMapper();
    if (payload.containsKey("seqNo")) {
        Sequence seq = objectMapper.convertValue(payload, Sequence.class);
        // other logic
    } else if (payload.containsKey("country")) {
        Country country = objectMapper.convertValue(payload, Country.class);
    }
    // the same for other types

    // FURTHER LOGIC WOULD BE HERE.
    return ResponseEntity.ok(response);
}

You can also try with deserialising to com.fasterxml.jackson.databind.JsonNode but it binds controller with Jackson which is not good from other side.

2 Comments

Map<String, Object>, I need to type cast the Object while using. Could it be costly?
@TAB, casting is not costly. In Java generics are replaced with casting everywhere and it works fine. So, using map in that way Integer seq = (Integer)payload.get("seqNo") is fine.
1

The answer by @Patrick Adler is absolutely correct. You can use Map as your parameter of the method. Two important additions: Map corresponds to JSON Object so when a JSON object is passed to your method Spring (using Jackson by default) will convert it to map, so no additional code needed. Also to be sure you can add to your annotation that you expect to receive JSON input: So change the line

@PostMapping(value = "/lookup")

to

@PostMapping(value = "/lookup", headers = "Accept=application/json")

And finally the input that you posted is not a valid single JSON Object. It is 3 separate JSON Objects. So either you expect a JSON array containing JSON Objects or a Single JSON Object. If you expect a JSON Array then instead of Map<String, Object> parameter in your method use List<Map<String, Object>> so your solution should look either

@PostMapping(value = "/lookup", headers = "Accept=application/json")
public ResponseEntity<AppResponse> getLookup(@RequestBody Map<String, Object> lookupRequestObject) {

    // THIS METHOD KNOWS WHICH FIELD TO USE
    // FURTHER LOGIC WOULD BE HERE.

    return ResponseEntity.ok(response);
}

or the same but with List<Map<String, Object>> param instead of just map

4 Comments

A little bit safer is List<Object> instead of List<Map<String, Object>> because in case of array of primitives [1,2,3] it will work by default.
Yes, I have a bit complicated JSON like, { 'seqNo': 10, 'sort': { 'field': 'ctry', 'desc': 0 } 'filter': { 'field': 'region', 'operator': 'startsWith', 'value': 'europe' } page: 0, size: 20, userData: { ... } }
@TAB, your JSON is fine in this case your parameter still is Map<String, Object>. it will work just fine. BTW if the solution works for you mark it as an accepted answer :)
MichaelGantman, Yes I am working and now I have almost done my work. Specially Thanks for MichaelGantman, @MichałZiober and PatrickAdler for your quick responses. Every answer help me but I have to mark just one as answer so... :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.