The problem found

It went online Tuesday night

  • The test environment is verified
  • The pre-release environment is verified
  • Start production

When production goes online, notify test for verification. The test starts to walk through the test cases and finds that they continue to fail. Urgent notice I am fart with colleagues, how can there be a problem? Advance is not verified through it? It’s absolutely fine. You try again. But it didn’t work. There was a real problem. Oh my God… What’s the problem?

Troubleshoot problems

After a check (look at the log records), it is found that the problem: the test environment and pre-sent environment messages are sent by their own consumption, after the steps of message serialization and deserialization, so the verification passed. The production environment is highly available, so messages are asynchronized, high availability is ensured through JMQ, and serialization and deserialization are utilized with JSON. The problem log was found here and the primary property was missing

Problem code:

Base event definition:

 
  
/ * * *@Title: EventMsg
 * @Description: Event message */
public class EventMsg {
 
    private String id;
    private String eventType;
    private String content;
 
    public EventMsg(a){}
 
    public EventMsg(String eventType, String content) {
        this.id = content;
        this.eventType = eventType;
        this.content = content;
    }
 
    public EventMsg(String eventType, String content, String id) {
        this.id = id;
        this.eventType = eventType;
        this.content = content;
    }
 
    public String getId(a) {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getEventType(a) {
        return eventType;
    }
 
    public void setEventType(String eventType) {
        this.eventType = eventType;
    }
 
    public String getContent(a) {
        return content;
    }
 
    public void setContent(String content) {
        this.content = content;
    }
 
    @Override
    public String toString(a) {
        return "EventMsg{" +
                "eventType=" + eventType +
                ", content='" + content + '\' ' +
                '} '; }}Copy the code

Product events that inherit from the base event definition:

This is to extend additional information about product domain events

 
/ * * *@date2021/1/15 * * /
public class ItemEvent extends EventMsg {
    #{ItemEventTypeEum} */
    private String itemEventType;
 
    /** * Distribution record ID */
    private Long distributId;
 
    public String getItemEventType(a) {
        return itemEventType;
    }
 
    public void setItemEventType(String itemEventType) {
        this.itemEventType = itemEventType;
    }
 
    public Long getDistributId(a) {
        return distributId;
    }
 
    public ItemEvent setDistributId(Long distributId) {
        this.distributId = distributId;
        return this;
    }
 
 
    public ItemEvent(a) {}public ItemEvent(String itemEventType, String content) {
        super(EventTypeEum.item.name(), content);
        this.itemEventType = itemEventType;
    }
 
    public ItemEvent(String itemEventType, String skuId, Long distributId) {
        super(EventTypeEum.item.name(), skuId);
        this.itemEventType = itemEventType;
        this.distributId = distributId; }}Copy the code

Notice that a new constructor is added here

    public ItemEvent(String itemEventType, String skuId, Long distributId) {
        super(EventTypeEum.item.name(), skuId);
        this.itemEventType = itemEventType;
        this.distributId = distributId;
    }
Copy the code

Complete the base event initialization by calling the parent. Note the CONTENT and skuId of the product message here.

public EventMsg(String eventType, String content, String id) {
        this.id = id;
        this.eventType = eventType;
        this.content = content;
    }
Copy the code

Unit testing:

`@Test`

`public` `void` `test_buildEventMsg() {`

`    ``String message = ``"{"content":"18468377001001000021","eventType":"item","id":"18468377001001000021","itemEventType":"UPDATED"}"` `; ` ` ``EventMsg eventMsg = EventListener.buildEventMsg(message); ` ` ``Assert.assertEquals(``true``, eventMsg ``instanceof` `ItemEvent); ` ` ``Assert.assertEquals(``"18468377001001000021"``, eventMsg.getContent()); ` `} ` `@Test`

`public` `void` `test_buildEventMsg_withDistributeId() {`

`    ``String message = ``"{"distributId": 111,"content":"18468377001001000021","eventType":"item","id":"18468377001001000021","itemEventType":"UPDATED"}"` `; ` ` ``EventMsg eventMsg = EventListener.buildEventMsg(message); ` ` ``Assert.assertEquals(``true``, eventMsg ``instanceof` `ItemEvent); ` ` ``Assert.assertEquals(``new` `Long(``111``), ((ItemEvent) eventMsg).getDistributId()); ` ` `}Copy the code

It turns out that the content is missing.

Why did you lose it?

1. When multiple constructors exist (there is no empty constructor), the one with the most arguments will be selected.

2. At the same time, the value of the field name is mapped based on the parameter name. If the parameter name is inconsistent with the name of the property (including the parent), the property fails to be obtained

Following the first explanation above, it turns out that the second constructor is actually called

public ItemEvent(String itemEventType, String content)
public ItemEvent(String itemEventType, String skuId, Long distributId)
Copy the code

According to the second check, the actual attribute should be Content, and skuId is passed in. ParseObject will automatically reflect properties through the parameter name, and it will find no setSkuId attribute assignment method, and it will be discarded. So you can see why content doesn’t have a value.

The solution:

  • Java Bean specification compliant, empty constructor exists
  • Adjust the constructor parameters to match the properties

This is a hole I’ve never noticed before. You can look at the code for parseObject.