Mapping JSON to Java Object return null value

2019-07-16 12:06发布

问题:

I want to parsing json object like this:

{ 
    "Count" : 1, 
    "Data" : [
        { 
           "ContactID" : 1567993182, 
           "Email"  : "enamdimensi@localhost.com", 
           "Action" : "unsub", 
           "Name" : "", 
           "Properties" : {} 
         }
      ], 
     "Total" : 1 
  }

to this java object.

public class Response {
     @JsonProperty("Status")
     private String status;
     @JsonProperty("Data")
     private List<DataResponse> data;
     @JsonProperty("Total")
     private Integer total;
     @JsonProperty("Count")
     private Integer count;

     public MailjetResponse() {
        super();
     }

     ........ setter and getter .......    
}

class DataResponse {
    @JsonProperty("ContactID")
    private String contactId;
    @JsonProperty("Name")
    private String name;
    @JsonProperty("Email")
    private String email;
    @JsonProperty("Action")
    private String action;
    @JsonProperty("Properties")
    private Map<String, Object> properties;

    public DataResponse() {
       super();
    }
    ....... setter and getter .....
}

I used Jackson to do that, and this is my code:

final ObjectMapper mapper = new ObjectMapper();
MailjetResponse response = mapper.readValue(content, Response.class);

But, if I debug the response, all of the fields Response is null.

response [Status=null, Data=null, Total=null, Count=null]

is there something wrong with my code ?

UPDATED CODE: Response class

public class Response {
@JsonProperty("Status")
private String status;
@JsonProperty("Data")
private List<DataResponse> data;
@JsonProperty("Total")
private Integer total;
@JsonProperty("Count")
private Integer count;

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

public Integer getTotal() {
    return total;
}

public void setTotal(Integer total) {
    this.total = total;
}

public Integer getCount() {
    return count;
}

public void setCount(Integer count) {
    this.count = count;
}

@Override
public String toString() {
    return "MailjetResponse [status=" + status + ", data=" + data
            + ", total=" + total + ", count=" + count + "]";
} 
}

DataResponse class

public class DataResponse {
@JsonProperty("ContactID")
private String contactId;
@JsonProperty("Name")
private String name;
@JsonProperty("Email")
private String email;
@JsonProperty("Action")
private String action;
@JsonProperty("Properties")
private Map<String, Object> properties;


public String getContactID() {
    return contactId;
}


public void setContactID(String contactID) {
    contactId = contactID;
}

public String getName() {
    return name;
}


public void setName(String name) {
    name = name;
}

public String getEmail() {
    return email;
}


public void setEmail(String email) {
    email = email;
}

public String getAction() {
    return action;
}

public void setAction(String action) {
    action = action;
}


@Override
public String toString() {
    return "DataResponse [contactId=" + contactId + ", name=" + name
            + ", email=" + email + ", action=" + action + ", properties="
            + properties + "]";
} 
}

There result bocome like this:

response MailjetResponse [status=null, data=[DataResponse [contactId=1567993182, name=null, email=null, action=null, properties={}]], total=1, count=1]

回答1:

    I have tried your example and used setter only and got email field populated after deserialisation of json.I could not see any other issue.

    Below is the code I have tried :

    public class Response {
        @JsonProperty("Status")
        private String status;
        @JsonProperty("Data")
        private List<DataResponse> data;
        @JsonProperty("Total")
        private Integer total;
        @JsonProperty("Count")
        private Integer count;

        public void setStatus(String status) {
            this.status = status;
        }

        public void setData(List<DataResponse> data) {
            this.data = data;
        }

        public void setTotal(Integer total) {
            this.total = total;
        }

        public void setCount(Integer count) {
            this.count = count;
        }
    }


    public class DataResponse {
        @JsonProperty("ContactID")
        private String contactId;
        @JsonProperty("Name")
        private String name;
        @JsonProperty("Email")
        private String email;
        @JsonProperty("Action")
        private String action;
        @JsonProperty("Properties")
        private Map<String, Object> properties;

        public void setContactId(String contactId) {
            this.contactId = contactId;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public void setAction(String action) {
            this.action = action;
        }

        public void setProperties(Map<String, Object> properties) {
            this.properties = properties;
        }
    }


 final ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        final Response response = mapper.readValue(message(), Response.class);

I will prefer to Jsoncreator annotated on constructor.



回答2:

Problem

The problem is in your setters.

public void setEmail(String email) {
    email = email;
}

This makes an unqualified assignment fron input arg email to ... input arg email (instead of the field this.email). It should be:

public void setEmail(String email) {
    this.email = email;
}

Jackson and annotated field access

Jackson uses setters unless configured otherwise. Either correct the setters (e.g. auto-generate them with IDE) or remove them and use fields only. To do that either annotate class with

@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class DataResponse {

or change mapper settings, e.g.

ObjectMapper mapper  = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

Also: if you correct setters you may drop field annotations... Pick whatever is best for your use case. I prefer my jackson serialization to be done with just fields, always annotated - or with mixins.