Here's the initial setup that I have
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);
I'd like to change the builder into the following alternative implementation, in which case the above Jackson setup stops finding the relationship between JSON file and the Jackson annotations and maps all the fields of the Message object to nulls.
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{
}
}
Is this something that Jackson framework supports and if so, what needs to change?
I'm using jackson version 2.9.4
Thank you in advance.
Turns out, this functionality is already present in Jackson while another issue had eclipsed it for me during testing. The below modified version of MessageBuilder
exhibits the functionality sought:
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{
}
}