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