Home > Software engineering >  Parse JSON into Map using Jackson Object Mapper
Parse JSON into Map using Jackson Object Mapper

Time:11-10

I have a Java Class which needs to store JSON in the form of a Map. But when I tried to parse using Jackson's ObjectMapper I've got an UnrecognizedPropertyException.

It was working earlier when the JSON structure was different. So the issue seems to be the Classes which I have defined to hold the JSON structure and read it as a Map.

Java Class

public class Code {
    private Map<String, Errors> codeMap;
    public Map<String, Errors> getCodeMap() {
        return codeMap;
    }
    public void setCodeMap(Map<String, Errors> codeMap) {
        this.codeMap = codeMap;
    }
}

public class Errors {
    private List<Error> error;

    public List<Error> getError() {
        return error;
    }

    public void setError(List<Error> error) {
        this.error = error;
    }
}

public class Error {

    private String errorCode;
    private String errorMsg;
    public String getErrorCode() {
        return errorCode;
    }
    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
    public String getErrorMsg() {
        return errorMsg;
    }
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
    
}

JSON file:

{
    "SpringErrors": [
        {
            "errorCode": "01",
            "errorMsg": "Invalid ID"
        }
    ],
    "JavaErrors": [
        {
            "errorCode": "02",
            "errorMsg": "Invalid ID2"
        }
    ]
}

Parsing Logic:

ObjectMapper mapper=new ObjectMapper();
Code code=mapper.readValue(new InputStreamReader(this.getClass().getResourceAsSream("sample.json")),Code.class);`

CodePudding user response:

Do you have a special reason for mapping SpringErrors and JavaErrors dynamically? Like you cannot expect what the field names are going to be?

If not check below mapping,

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

class Code {
    @JsonProperty("SpringErrors")
    private List<Error> springErrors;
    @JsonProperty("JavaErrors")
    private List<Error> javaErrors;

    public List<Error> getSpringErrors() {
        return springErrors;
    }

    public void setSpringErrors(List<Error> springErrors) {
        this.springErrors = springErrors;
    }

    public List<Error> getJavaErrors() {
        return javaErrors;
    }

    public void setJavaErrors(List<Error> javaErrors) {
        this.javaErrors = javaErrors;
    }
}

class Error {

    private String errorCode;
    private String errorMsg;
    public String getErrorCode() {
        return errorCode;
    }
    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
    public String getErrorMsg() {
        return errorMsg;
    }
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

}

class Main {

    static final String json = "{\n"
              "    \"SpringErrors\": [\n"
              "        {\n"
              "            \"errorCode\": \"01\",\n"
              "            \"errorMsg\": \"Invalid ID\"\n"
              "        }\n"
              "    ],\n"
              "    \"JavaErrors\": [\n"
              "        {\n"
              "            \"errorCode\": \"02\",\n"
              "            \"errorMsg\": \"Invalid ID2\"\n"
              "        }\n"
              "    ]\n"
              "}";

    public static void main(String[] args) {

        ObjectMapper mapper=new ObjectMapper();
        InputStream targetStream = new ByteArrayInputStream(json.getBytes());
        try {
            Code code = mapper.readValue(new InputStreamReader(targetStream),Code.class);
            System.out.println(mapper.writeValueAsString(code));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

CodePudding user response:

The structure of your incoming JSON doesn't match the structure of your Code class.

And each value in the JSON represents a JSON-array, not an object wrapping a JSON-array, hence it doesn't match the Errors class.

To address this issue, you need to implement the parsing logic yourself.

To preserve the ability to handle dynamic data, you can introduce a method responsible for handling each property and its corresponding value in the incoming JSON. This method should be annotated with @JsonAnySetter.

The arguments of the method would be a String a property name and a JsonNode representing a corresponding value.

public class Code {
    private Map<String, Errors> codeMap = new HashMap<>();
    
    @JsonAnySetter
    public void parseEntries(String key, JsonNode value) throws IOException {
        
        ObjectReader reader = new ObjectMapper().readerFor(new TypeReference<>() {});
        List<Error> errors = reader.readValue(value);
        
        codeMap.put(key, new Errors(errors));
    }

    public Map<String, Errors> getCodeMap() {
        return codeMap;
    }
    
    @JsonIgnore
    public void setCodeMap(Map<String, Errors> codeMap) {
        this.codeMap = codeMap;
    }
}

CodePudding user response:

Code.codeMap should be:

private Map<String, List<Errors>> codeMap;

because the errors are in lists in the JSON

  • Related