When fasterxml jackson deserializes, an error is reported for non-static inner classes

Java usually uses two libraries, jackson and fastjson, to process json. The latter API is more convenient to use, but there are too many security holes.

Today, when using jackson to deserialize a json string, I encountered a problem:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `json.TransferResp$TransforData` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor

Many articles did not explain clearly, this article did an experiment. For the nested structure, a java class containing an inner class is defined to receive it. If the complex structure is in the form of an array, the above error will be reported when deserializing.

experiment one

1) java entity class:

@Data
public class TransforResponse {
    private Integer code;
    
    private Map<String, String> defaultData;
    private TransforData data;
    
    @Data
    public static class TransforData{
        private Long encyId;
        private int score;
        private Map<String, String> other;
    }
}

2) test

private static ObjectMapper objectMapper = new ObjectMapper();

public static void main(String[] args) throws Exception {
    String jsonStr = serialization(); //{\"code\":200,\"data\":{\"encyId\":123,\"other\":{\"a\":\"test\"},\"score\":5}}
    deSerialization(jsonStr); //TransferResp(code=200, data=TransferResp.TransforData(encyId=123, score=5, other={a=test}))
    
    System.out.println("----------");
    String jsonStr2 = serialization2(); //{\"code\":200,\"data\":{\"encyId\":123,\"other\":{\"a\":\"test\"},\"score\":5}}
    deSerialization2(jsonStr2); //TransferResp(code=200, data=TransferResp.TransforData(encyId=123, score=5, other={a=test}))
}
private static TransferResp createObj() {
    TransferResp tr = new TransferResp();
    
    TransforData transforData = tr.new TransforData();
    transforData.setEncyId(123L);
    transforData.setScore(5);
    Map<String, String> hashMap = new HashMap<>(1);
    hashMap.put("a", "test");
    transforData.setOther(hashMap);
    
    tr.setCode(200);
    tr.setData(transforData);

    return tr;
}

private static String serialization() {
    TransferResp tr = createObj();
    String jsonString = JSONObject.toJSONString(tr);
    System.out.println(jsonString);
    return jsonString;
}
private static void deSerialization(String jsonStr) {
    TransferResp parseObject = JSONObject.parseObject(jsonStr, TransferResp.class);
    System.out.println(parseObject.toString());
}

private static String serialization2() throws JsonProcessingException {
    TransferResp tr = createObj();
    String jsonString = objectMapper.writeValueAsString(tr);
    System.out.println(jsonString);
    return jsonString;
}
private static void deSerialization2(String jsonStr) throws JsonParseException, JsonMappingException, IOException {
    TransferResp parseObject = objectMapper.readValue(jsonStr, TransferResp.class);
    System.out.println(parseObject.toString());
}

 After running it is normal.

Experiment 2

1) java entity class

@Data
public class TransferResp {
    private Integer code;
    private List<TransforData> data;
    
    @Data
    public class TransforData{
        private Long encyId;
        private Integer score;
        private Map<String, String> other;
    }
}

2) Test:

private static ObjectMapper objectMapper = new ObjectMapper();

public static void main(String[] args) throws Exception {
    String jsonStr = serialization(); //{"code":200,"data":[{"encyId":123,"other":{"a":"test"},"score":5}]}
    deSerialization(jsonStr); //TransferResp(code=200, data=[TransferResp.TransforData(encyId=123, score=5, other={a=test})])
    
    System.out.println("----------");
    String jsonStr2 = serialization2(); //{"code":200,"data":[{"encyId":123,"score":5,"other":{"a":"test"}}]}
    deSerialization2(jsonStr2); //error
}
private static TransferResp createObj() {
    TransferResp tr = new TransferResp();
    
    TransforData transforData = tr.new TransforData();
    transforData.setEncyId(123L);
    transforData.setScore(5);
    Map<String, String> hashMap = new HashMap<>(1);
    hashMap.put("a", "test");
    transforData.setOther(hashMap);
    
    List<TransforData> list = new ArrayList<>();
    list.add(transforData);
    tr.setCode(200);
    tr.setData(list);

    return tr;
}

private static String serialization() {
    TransferResp tr = createObj();
    String jsonString = JSONObject.toJSONString(tr);
    System.out.println(jsonString);
    return jsonString;
}
private static void deSerialization(String jsonStr) {
    TransferResp parseObject = JSONObject.parseObject(jsonStr, TransferResp.class);
    System.out.println(parseObject.toString());
}

private static String serialization2() throws JsonProcessingException {
    TransferResp tr = createObj();
    String jsonString = objectMapper.writeValueAsString(tr);
    System.out.println(jsonString);
    return jsonString;
}
private static void deSerialization2(String jsonStr) throws JsonParseException, JsonMappingException, IOException {
    TransferResp parseObject = objectMapper.readValue(jsonStr, TransferResp.class);
    System.out.println(parseObject.toString());
}

运行时会报错:Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `json.TransferResp$TransforData` (although at least one Creator exists): can only instantiate non-static inner class by using default, no-argument constructor

3) Solution:

A. Use static inner classes

@Data
public class TransferResp {
    private Integer code;
    private List<TransforData> data;
    
    @Data
    public static class TransforData{
        private Long encyId;
        private Integer score;
        private Map<String, String> other;
    }
}

B) Define the inner class in a separate class file.

Guess you like

Origin blog.csdn.net/liuxiao723846/article/details/129070511