有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Jackson中正确反序列化映射<String,Object>

我有以下可以序列化为字节或json的POJO

public final class Message {

  private final Data data;
  private final Request request;
  private final Response response;

  public Message() {
    this.data = new Data();
    this.request = new Request();
    this.response = new Response();
  }

  public Data getData() {
    return data;
  }

  public Request getRequest() {
    return request;
  }

  public Response getResponse() {
    return response;
  }

  public Object query(String pointer) {
    return toJson().query(pointer);
  }

  public byte[] toBytes() {
    try {
      return new ObjectMapper(new MessagePackFactory()).writeValueAsBytes(this);
    } catch (JsonProcessingException ex) {
      throw new MessageException(ex);
    }
  }

  public JSONObject toJson() {
    try {
      return new JSONObject(new ObjectMapper().writeValueAsString(this));
    } catch (JsonProcessingException ex) {
      throw new MessageException(ex);
    }
  }

  @Override
  public String toString() {
    try {
      return toString(0);
    } catch (MessageException ex) {
      throw new MessageException(ex);
    }
  }

  public String toString(int indent) {
    try {
      return toJson().toString(indent);
    } catch (MessageException ex) {
      throw new MessageException(ex);
    }
  }
}

参考类:

public class Data {

  private final Map<String, Map<String, Object>> dataMap;

  public Data() {
    this.dataMap = new HashMap();
  }

  public Data addToSet(String name, String key, Object value) {
    Map<String, Object> map = dataMap.get(name);
    if (map == null) {
      map = new HashMap();
    }
    map.put(key, value);
    dataMap.put(name, map);
    return this;
  }

  public Map<String, Map<String, Object>> getSets() {
    return dataMap;
  }

  public Data updateSet(String name, String key, Object value) {
    return Data.this.addToSet(name, key, value);
  }

  public Data removeFromSet(String name, String key) {
    Map<String, Object> map = dataMap.get(name);
    if (map == null) {
      throw new MessageException("No such property '" + key + "' for set '" + name + "'");
    }
    map.remove(key);
    return this;
  }

  public Map<String, Object> getSet(String name) {
    return dataMap.get(name);
  }
}
public class Request {

  private String method;
  private String resource;
  private final Map<String, Object> body;
  private final Map<String, String> headers;
  private final Map<String, String[]> parameters;

  public Request() {
    this.body = new HashMap();
    this.headers = new HashMap();
    this.parameters = new HashMap();
  }

  public String getMethod() {
    return Objects.toString(method, "");
  }

  public String getResource() {
    return Objects.toString(resource, "");
  }

  public Map<String, Object> getBody() {
    return body;
  }

  public Map<String, String> getHeaders() {
    return headers;
  }

  public Map<String, String[]> getParameters() {
    return parameters;
  }

  public String getHeader(String name) {
    return headers.get(name);
  }

  public Request setBody(String payload) {
    try {
      this.body.putAll(new ObjectMapper().readValue(payload, new TypeReference<Map<String, Object>>() {
      }));
      return this;
    } catch (JsonProcessingException ex) {
      throw new MessageException(ex);
    }
  }

  public Request setMethod(String name) {
    this.method = name;
    return this;
  }

  public Request setResource(String name) {
    this.resource = name;
    return this;
  }

  public Request setHeaders(Map<String, String> headers) {
    this.headers.putAll(headers);
    return this;
  }

  public Request setParameters(Map<String, String[]> parameters) {
    this.parameters.putAll(parameters);
    return this;
  }
}
public class Response {

  private String code;
  private String data;
  private String messageId;
  private String timestamp;
  private String description;

  public Response() {
  }

  public String getCode() {
    return Objects.toString(code, "");
  }

  public String getData() {
    return Objects.toString(data, "");
  }

  public String getMessageId() {
    return Objects.toString(messageId, "");
  }

  public String getTimestamp() {
    return Objects.toString(timestamp, "");
  }

  public String getDescription() {
    return Objects.toString(description, "");
  }

  public Response setCode(String code) {
    this.code = code;
    return this;
  }

  public Response setData(String data) {
    this.data = data;
    return this;
  }

  public Response setMessageId(String messageId) {
    this.messageId = messageId;
    return this;
  }

  public Response setTimestamp(String timestamp) {
    this.timestamp = timestamp;
    return this;
  }

  public Response setDescription(String description) {
    this.description = description;
    return this;
  }
}

当序列化为json时,我会得到一个有效的字符串

{
    "request": {
        "headers": {},
        "method": "",
        "resource": "",
        "body": {
            "whatsapp": {
                "conversationId": "39f09c41-1bd3-4e81-b829-babed3747d4b",
                "name": "Dave",
                "source": "+123456789098"
            },
            "payment": {
                "product": "chocolate",
                "amount": 1,
                "method": "cashapp",
                "msisdn": "123456789098",
                "entity": "The Fudge Shop"
            }
        },
        "parameters": {}
    },
    "data": {
        "sets": {
            "whatsapp": {
                "provider": "clickatell",
                "name": "Dave",
                "destination": "123456789098",
                "source": "123456789098",
                "message": "Your payment of $1.00 received, your receipt.no is QWJ124XPA9."
            },
            "cashapp": {
                "amount": 1,
                "receiptNo": "QWJ124XPA9",
                "name": "Dave Chapelle",
                "msisdn": "123456789098"
            }
        }
    },
    "response": {
        "code": "202",
        "data": "",
        "messageId": "20210623160202a647d32ee9ae477f9c90d8b1fbfd763a",
        "description": "Processing Request",
        "timestamp": "2021-06-23 16:02:02.408"
    }
}

当我尝试将json反序列化回pojo时

Message output = new ObjectMapper().readValue(json.toString(), Message.class);

我得到一个错误:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

尝试反序列化Map<String, Object>正文时,似乎从请求类生成了错误:

如何正确反序列化地图


共 (3) 个答案

  1. # 1 楼答案

    对于字符串问题,以下来源可能会有所帮助:

    Can not deserialize instance of java.lang.String out of START_OBJECT token

    https://www.baeldung.com/jackson-map#1-mapltstring-stringgt-deserialization

    为什么此代码无法工作

    杰克逊并不比你强大多少

    如果Jackson获取要序列化的对象,它将尝试序列化其所有值。而且只有它的值(这对于独立于类是非常好的)。这是一个json对象:

    {
    "type":"apple",
    "quantity":3,
    "imageID":17
    }
    

    现在,这个对象的类是什么?它可能是Fruit.classImage.class甚至RoundObject.class,json不知道,Jackson也不知道

    那么json如何发现类是什么呢?通过查看对象引用的类型。在你的情况下,它是对象。在对象中。类,Jackson找不到需要已保存对象的变量的构造函数,因此它崩溃

    解决方案

    尝试序列化对象不是一个好主意。如果您想要放入非常不同的类,例如AppleBanana,则创建一个名为interfaceabstract classFruit的类,这两个类都实现。现在,在此类顶部使用此注释:

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            property = "type") // name of the variable to save the kind of object you put in. NO VARIABLES in all classes that extend from Fruit are allowed to have this name (or at least @JsonProperty).
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Apple.class, name = "banana"),
            @JsonSubTypes.Type(value = Banana.class, name = "apple"),
    })
    

    以及使用地图<;水果串>;应该有用

  2. # 2 楼答案

    对我有效的解决方案是使用自定义反序列化、@JsonDeserialize注释&JsonDeserializer接口,以实现所需的结果

    以下是解决方案:

    public class Request {
    
      private String method;
      private String resource;
      @JsonDeserialize(using = BodyDeserializer.class)
      private final Map<String, Object> body;
      private final Map<String, String> headers;
      private final Map<String, String[]> parameters;
    
      public Request() {
        this.body = new HashMap();
        this.headers = new HashMap();
        this.parameters = new HashMap();
      }
    
      public String getMethod() {
        return method;
      }
    
      public String getResource() {
        return resource;
      }
    
      public Map<String, Object> getBody() {
        return body;
      }
    
      public Map<String, String> getHeaders() {
        return headers;
      }
    
      public Map<String, String[]> getParameters() {
        return parameters;
      }
    
      public String getHeader(String name) {
        return headers.get(name);
      }
    
      public Request setBody(Map<String, Object> body) {
        this.body.putAll(body);
        return this;
      }
    
      public Request setMethod(String name) {
        this.method = name;
        return this;
      }
    
      public Request setResource(String name) {
        this.resource = name;
        return this;
      }
    
      public Request setHeaders(Map<String, String> headers) {
        this.headers.putAll(headers);
        return this;
      }
    
      public Request setParameters(Map<String, String[]> parameters) {
        this.parameters.putAll(parameters);
        return this;
      }
    
      private static class BodyDeserializer extends JsonDeserializer<Map<String, Object>> {
    
        @Override
        public Map<String, Object> deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
          JsonDeserializer<Object> deserializer = dc.findRootValueDeserializer(dc.constructType(Map.class));
          Map<String, Object> map = (Map<String, Object>) deserializer.deserialize(jp, dc);
          return map;
        }
      }
    }
    
  3. # 3 楼答案

    试试这个JacksonUtils

    Message actual = createMessage();
    String json = JsonUtils.prettyPrint().writeValue(actual);
    System.out.println(json);
    Message expected = JsonUtils.readValue(json, Message.class);
    

    这是完整的代码片段:

    public class MavenMain {
        public static void main(String... args) {
            Message actual = createMessage();
            String json = JsonUtils.prettyPrint().writeValue(actual);
            System.out.println(json);
            Message expected = JsonUtils.readValue(json, Message.class);
        }
    
        private static Message createMessage() {
            Message message = new Message();
            message.setData(createData());
            message.setRequest(createRequest());
            message.setResponse(createResponse());
            return message;
        }
    
        private static Data createData() {
            Map<String, Object> whatsapp = new LinkedHashMap<>();
            whatsapp.put("provider", "clickatell");
            whatsapp.put("name", "Dave");
            whatsapp.put("destination", "123456789098");
            whatsapp.put("source", "123456789098");
            whatsapp.put("message", "Your payment of $1.00 received, your receipt.no is QWJ124XPA9.");
    
            Map<String, Object> cashapp = new LinkedHashMap<>();
            cashapp.put("receiptNo", "QWJ124XPA9");
            cashapp.put("name", "Dave Chapelle");
            cashapp.put("msisdn", "123456789098");
    
            Map<String, Map<String, Object>> dataMap = new LinkedHashMap<>();
            dataMap.put("whatsapp", whatsapp);
            dataMap.put("cashapp", cashapp);
    
            Data data = new Data();
            data.setDataMap(dataMap);
    
            return data;
        }
    
        private static Request createRequest() {
            Map<String, Object> whatsapp = new LinkedHashMap<>();
            whatsapp.put("conversationId", "39f09c41-1bd3-4e81-b829-babed3747d4b");
            whatsapp.put("name", "Dave");
            whatsapp.put("source", "+123456789098");
    
            Map<String, Object> payment = new LinkedHashMap<>();
            payment.put("product", "chocolate");
            payment.put("amount", 1);
            payment.put("method", "cashapp");
            payment.put("msisdn", "123456789098");
            payment.put("entity", "The Fudge Shop");
    
            Map<String, Object> body = new HashMap<>();
            body.put("whatsapp", whatsapp);
            body.put("payment", payment);
    
            Request request = new Request();
            request.setHeaders(Collections.emptyMap());
            request.setMethod("");
            request.setResource("");
            request.setBody(body);
            request.setParameters(Collections.emptyMap());
    
            return request;
        }
    
        private static Response createResponse() {
            Response response = new Response();
            response.setCode("202");
            response.setData("");
            response.setMessageId("20210623160202a647d32ee9ae477f9c90d8b1fbfd763a");
            response.setDescription("Processing Request");
            response.setTimestamp("2021-06-23T16:02:02.408");
            return response;
        }
    }
    
    class Message {
    
        private Data data;
        private Request request;
        private Response response;
    
        public void setData(Data data) {
            this.data = data;
        }
    
        public void setRequest(Request request) {
            this.request = request;
        }
    
        public void setResponse(Response response) {
            this.response = response;
        }
    }
    
    class Data {
    
        @JsonProperty("sets")
        private Map<String, Map<String, Object>> dataMap;
    
        public void setDataMap(Map<String, Map<String, Object>> dataMap) {
            this.dataMap = dataMap;
        }
    }
    
    class Request {
    
        private String method;
        private String resource;
        private Map<String, Object> body;
        private Map<String, String> headers;
        private Map<String, String[]> parameters;
    
        public void setMethod(String method) {
            this.method = method;
        }
    
        public void setResource(String resource) {
            this.resource = resource;
        }
    
        public void setBody(Map<String, Object> body) {
            this.body = body;
        }
    
        public void setHeaders(Map<String, String> headers) {
            this.headers = headers;
        }
    
        public void setParameters(Map<String, String[]> parameters) {
            this.parameters = parameters;
        }
    }
    
    class Response {
    
        private String code;
        private String data;
        private String messageId;
        private String timestamp;
        private String description;
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public void setData(String data) {
            this.data = data;
        }
    
        public void setMessageId(String messageId) {
            this.messageId = messageId;
        }
    
        public void setTimestamp(String timestamp) {
            this.timestamp = timestamp;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    }
    

    如果您想使用immutable对象,那么它是另一种模型配置,但是main类中的代码将是相同的