This is the 30th day of my participation in the Wenwen Challenge

The business scenario

In the process of device communication service development, the following scenarios are generated:

Device one detects the message -> sends MQTT details -> Device two receives the message and processes it

In this process, Jackson is used to handle the conversion between data and JSON strings

This is where the problem arises

Analysis of the

In the message entity, we have a setter method like this:

public class MqttInfo {
    private List<String> names;
    private List<String> suffixNames;
    
    public void setNames(List<String> names) {
        this.names = names;
        this.suffixNames = names.stream().filter(name -> name.contains("test")).collect(Collectors.toList()); }}Copy the code

When Jackson parses the JSON string, he calls the setter method of the entity class. If the json form is {“names”: null}, the null pointer exception will be thrown on the second line of the setter method

plan

There are three ways to solve the problem:

  1. Modifying setter methods
  2. No NULL value is passed
  3. Configure Jackson to automatically ignore null values

Modifying setter methods

We just need to do a null check, which is Optional:

public class MqttInfo {
    private List<String> names;
    private List<String> suffixNames;
    
    public void setNames(List<String> names) {
        this.names = names;
        Optional.ofNullable(names).ifPresent(data -> {
            this.suffixNames = data.stream().filter(name -> name.contains("test")).collect(Collectors.toList()); }); }}Copy the code

No NULL value is passed

If the conversion process can be controlled

We can manually modify the pass-value logic to add default values and so on

Eliminate null values in JSON

Configure Jackson to automatically ignore null values

First, let’s show you how we converted json:

public class MqttUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    private static void sendMessage(MqttPahoMessageHandler handler, String topic, Object data) {
        try {
            String json = MAPPER.writeValueAsString(data);
            Message<String> mqttMessage = MessageBuilder.withPayload(json).setHeader(MqttHeaders.TOPIC, topic).setHeader(MqttHeaders.QOS, DEFAULT_QOS).build();
            handler.handleMessage(mqttMessage);
        } catch (JsonProcessingException e) {
            throw new MqttException("Json conversion failed", e); }}}Copy the code

We can add the following initialization configuration to prevent null problems:

public class MqttUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    static {
        MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }
    
    private static void sendMessage(MqttPahoMessageHandler handler, String topic, Object data) {
        try {
            String json = MAPPER.writeValueAsString(data);
            Message<String> mqttMessage = MessageBuilder.withPayload(json).setHeader(MqttHeaders.TOPIC, topic).setHeader(MqttHeaders.QOS, DEFAULT_QOS).build();
            handler.handleMessage(mqttMessage);
        } catch (JsonProcessingException e) {
            throw new MqttException("Json conversion failed", e); }}}Copy the code

Configure (jsonParser.feature.allow_comments, true)

Json allows annotation formats, but of course, converted data is not affected

conclusion

Considering the robustness of the program, I recommend using both the first method and the third method