在 (de)/序列化期间,Jackson 可以使用具有包含在 java.util.Map 中的属性的构建器吗?

Can Jackson use a builder with properties contained in a java.util.Map during (de)/serialization?

这是我的初始设置

String json = "{'text': 'what is my balance', 'mid': 'D1dexnEBTCefEdRWveEt8A', 'seq': 73}";

import java.io.Serializable;
import java.time.LocalDateTime;

import org.apache.commons.lang3.builder.EqualsBuilder;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(builder = Messages.MessageBuilder.class)
public class Message implements Serializable {

  @JsonProperty("id")
  public final String id;

  @JsonProperty("botId")
  public final String botId;

  @JsonProperty("userId")
  public final String userId;

  public final String userIdKey;

  public boolean echoText=false;

  public String text;

  public String timeZone;

  public volatile String username;

  @JsonProperty("conversationId")
  public volatile String conversationId;

  public volatile int kaiUserId;

  public volatile String token;

  public final LocalDateTime inboundReceivedAt;

  public volatile LocalDateTime outboundSentAt;

  final String key;

  private final int _hashCode;

  public volatile long lastAccess = System.currentTimeMillis();

  public Message(final String pMessageId, final String pUserId, final String pBotId, final String pConversationId, final String pText) {
    id = pMessageId;
    userId = pUserId;
    botId = pBotId;
    conversationId = pConversationId;
    text = pText;
    inboundReceivedAt = LocalDateTime.now();

    key = id + "-" + userId + "-" + botId;
    userIdKey = userId + "~" + botId;

    _hashCode = key.hashCode();
  }

  void touch() { lastAccess = System.currentTimeMillis(); }

  @Override public int hashCode() { return _hashCode; }

  @Override public boolean equals(final Object pObject) {
    if (!(pObject instanceof Message)) { return false; }
    return new EqualsBuilder().append(id, ((Message)pObject).id)
                              .append(botId, ((Message)pObject).botId)
                              .append(userId, ((Message)pObject).userId)
                              .isEquals();
  }

  private static final long serialVersionUID = 42L;
}

/**
 * Jackson backed implementation of {@link Serializer}
 */
public final class JacksonSerializer implements Serializer {

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.registerModule(new JavaTimeModule());
        mapper.configure(ALLOW_SINGLE_QUOTES, true);
    }

    /**
     * For testing purposes.
     */
    static void setMapper(ObjectMapper objectMapper) {
        mapper = objectMapper;
    }

    @Override
    public <T> String serialize(T t) {
        try {
            return mapper.writeValueAsString(t);
        } catch (Exception e) {
            throw new DatabindException("Serialization error", e);
        }
    }

    @Override
    public <T> void serialize(T object, OutputStream outputStream) {
        try {
            mapper.writeValue(outputStream, object);
        } catch (Exception e) {
            throw new DatabindException("Serialization error");
        }
    }

    @Override
    public <T> void serialize(T object, File file) {
        try {
            mapper.writeValue(file, object);
        } catch (Exception e) {
            throw new DatabindException("Serialization error");
        }
    }

    @Override
    public <T> T deserialize(String s, Class<T> aClass) {
        try {
            return mapper.readValue(s, aClass);
        } catch (Exception e) {
            throw new DatabindException("Deserialization error", e);
        }
    }

    @Override
    public <T> T deserialize(InputStream inputStream, Class<T> type) {
        try {
            return mapper.readValue(inputStream, type);
        } catch (Exception e) {
            throw new DatabindException("Deserialization error", e);
        }
    }

    @Override
    public <T> T deserialize(File file, Class<T> type) {
        try {
            return mapper.readValue(file, type);
        } catch (Exception e) {
            throw new DatabindException("Deserialization error", e);
        }
    }

}

public final class Messages {


    private Messages(){}

    public static MessageBuilder standard() {
        return new MessageBuilder();
    }



    public final static class MessageBuilder {

        @JsonProperty("mid")
        String id;

        String userId;
        String botId;
        String conversationId;

        @JsonProperty("text")
        String text;



        public MessageBuilder withId(String id) {
            this.id = id;
            return this;
        }

        @JsonProperty("userId")
        public MessageBuilder withUserId(String userId) {
            this.userId = userId;
            return this;
        }

        @JsonProperty("botId")
        public MessageBuilder withBotId(String botId) {
            this.botId = botId;
            return this;
        }

        @JsonProperty("conversationId")
        public MessageBuilder withConversationId(String conversationId) {
            this.conversationId = conversationId;
            return this;
        }

        public MessageBuilder withText(String text) {
            this.text = text;
            return this;
        }

        public Message build() {
            Message result = null;
            result = new Message(id, userId, botId, conversationId, text);
            return result;
        }

    }

    public final static class PushMessageBuilder{

    }
}

@Test
public void deserializationTest() {
    Serializer serializer = new JacksonSerializer();


    String json = "{'text': 'what is my balance', 'mid': 'D1dexnEBTCefEdRWveEt8A', 'seq': 73}";
    Message message = serializer.deserialize(json, Message.class);

我想将构建器更改为以下替代实现,在这种情况下,上述 Jackson 设置将停止查找 JSON 文件与 Jackson 注释之间的关系并映射 Message 对象的所有字段为空。

public final class Messages {


    private Messages(){}

    public static MessageBuilder standard() {
        return new MessageBuilder();
    }



    public final static class MessageBuilder {


       /*@JsonProperty("mid")
        String id;

        String userId;
        String botId;
        String conversationId;

        @JsonProperty("text")
        String text;*/


        @SuppressWarnings("serial")
        private Map<String, String> state = new HashMap<String, String>() {};

        @JsonProperty("mid")
        public MessageBuilder withId(String id) {
            state.put("id", id);
            //this.id = id;
            return this;
        }


        public MessageBuilder withUserId(String userId) {
            state.put("userId", userId);
            //this.userId = userId;
            return this;
        }


        public MessageBuilder withBotId(String botId) {
            state.put("botId", botId);
            //this.botId = botId;
            return this;
        }


        public MessageBuilder withConversationId(String conversationId) {
            state.put("conversationId", conversationId);
            //this.conversationId = conversationId;
            return this;
        }

        @JsonProperty("text")
        public MessageBuilder withText(String text) {
            state.put("text", text);
            //this.text = text;
            return this;
        }

        public Message build() {
            Message result = null;
            result = new Message(state.get("id"), 
                                 state.get("userId"), 
                                 state.get("botId"), 
                                 state.get("conversationId"), 
                                 state.get("text"));
            /*result = new Message(id, userId, botId, conversationId, text);*/
            return result;
        }

    }

    public final static class PushMessageBuilder{

    }
}

这是 Jackson 框架支持的东西吗?如果是,需要更改什么?

我使用的是 jackson 版本 2.9.4

提前致谢。

事实证明,此功能已存在于 Jackson 中,而在测试期间另一个问题对我来说已经黯然失色。 MessageBuilder 的以下修改版本展示了所寻求的功能:

public final class Messages {


    private Messages(){}

    public static MessageBuilder standard() {
        return new MessageBuilder();
    }



    public final static class MessageBuilder {

        /*@JsonProperty("mid")
        String id;

        String userId;
        String botId;
        String conversationId;

        @JsonProperty("text")
        String text;*/


        @SuppressWarnings("serial")
        private Map<String, String> state = new HashMap<String, String>() {};

        @JsonProperty("mid")
        public MessageBuilder withId(String id) {
            state.put("id", id);
            //this.id = id;
            return this;
        }

        //@JsonProperty("userId")
        public MessageBuilder withUserId(String userId) {
            state.put("userId", userId);
            //this.userId = userId;
            return this;
        }

        //@JsonProperty("botId")
        public MessageBuilder withBotId(String botId) {
            state.put("botId", botId);
            //this.botId = botId;
            return this;
        }

        //@JsonProperty("conversationId")
        public MessageBuilder withConversationId(String conversationId) {
            state.put("conversationId", conversationId);
            //this.conversationId = conversationId;
            return this;
        }

        @JsonProperty("text")
        public MessageBuilder withText(String text) {
            state.put("text", text);
            //this.text = text;
            return this;
        }

        public Message build() {
            Message result = null;
            result = new Message(state.get("id"), 
                                 state.get("userId"), 
                                 state.get("botId"), 
                                 state.get("conversationId"), 
                                 state.get("text"));
            //result = new Message(id, userId, botId, conversationId, text);
            return result;
        }

    }

    public final static class PushMessageBuilder{

    }
}