Today, I bump into a problem when fixing a unit test when asserting Jackson XML deserialized string.
Problem
Jackson XML deserialize null and empty value.
POJO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Data //lombok
@JacksonXmlRootElement(localName = "student")
@JsonPropertyOrder({"id", "_isClassRep", "_isActive", "name", "phone"})
class Student {
@JacksonXmlProperty(isAttribute = true, localName = "map")
private String id;
@JacksonXmlProperty(isAttribute = true, localName = "_isActive")
private boolean isActive;
@JacksonXmlProperty(isAttribute = true, localName = "_isClassRep")
private boolean isClassRep;
private String phone;
private String name;
private String address = "";
@JacksonXmlElementWrapper(localName = "subjects")
@JacksonXmlProperty(localName = "subject")
private List<String> subjects = new ArrayList<>();
}
Deserialization
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
Student student = new Student();
student.setId("id");
student.setActive(true);
student.setPhone("1234567890");
XmlMapper xmlMapper = new XmlMapper();
ByteArrayOutputStream bs = new ByteArrayOutputStream();
xmlMapper.writerWithDefaultPrettyPrinter().writeValue(bs, student);
String xmlString = bs.toString();
System.out.println(xmlString);
}
Output
1
2
3
4
5
6
<student map="id" _isClassRep="false" _isActive="true">
<name/>
<phone>1234567890</phone>
<address></address>
<subjects/>
</student>
We don’t wan Jackson to include name
, address
and subjects
. Instead our expecting deserialized XML string would be:
1
2
3
<student map="id" _isClassRep="false" _isActive="true">
<phone>1234567890</phone>
</student>
Solution
We can tell Jackson to ignore null or empty value by using
Include.NON_NULL
- only include properties with not null value in XML.Include.NON_EMPTY
- only include properties is not null / empty. E.g.List
/Map
- methodisEmpty()
return true ;String
with length 0.
There is few way we can do.
-
Supply
Include.NON_NULL
orInclude.NON_EMPTY
at property level.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
@Data //lombok @JacksonXmlRootElement(localName = "student") @JsonPropertyOrder({"id", "_isClassRep", "_isActive", "name", "phone"}) class Student { @JacksonXmlProperty(isAttribute = true, localName = "map") private String id; @JacksonXmlProperty(isAttribute = true, localName = "_isActive") private boolean isActive; @JacksonXmlProperty(isAttribute = true, localName = "_isClassRep") private boolean isClassRep; @JsonInclude(JsonInclude.Include.NON_NULL) private String phone; private String name; @JsonInclude(JsonInclude.Include.NON_EMPTY) private String address = ""; @JacksonXmlElementWrapper(localName = "subjects") @JacksonXmlProperty(localName = "subject") @JsonInclude(JsonInclude.Include.NON_EMPTY) private List<String> subjects = new ArrayList<>(); }
-
Supply
Include.NON_NULL
orInclude.NON_EMPTY
at class level.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
@Data //lombok @JacksonXmlRootElement(localName = "student") @JsonPropertyOrder({"id", "_isClassRep", "_isActive", "name", "phone"}) @JsonInclude(JsonInclude.Include.NON_EMPTY) class Student { @JacksonXmlProperty(isAttribute = true, localName = "map") private String id; @JacksonXmlProperty(isAttribute = true, localName = "_isActive") private boolean isActive; @JacksonXmlProperty(isAttribute = true, localName = "_isClassRep") private boolean isClassRep; private String phone; private String name; private String address = ""; @JacksonXmlElementWrapper(localName = "subjects") @JacksonXmlProperty(localName = "subject") private List<String> subjects = new ArrayList<>(); }
Note:
Include.NON_EMPTY
at class level means any property of this class that have empty value will not be included in XML. -
Supply
Include.NON_NULL
orInclude.NON_EMPTY
at global level with XmlMapper.1 2 3 4 5 6 7 8 9 10 11 12 13 14
public static void main(String[] args) { Student student = new Student(); student.setId("id"); student.setActive(true); student.setPhone("1234567890"); XmlMapper xmlMapper = new XmlMapper(); xmlMapper.setSerializationInclusion(Include.NON_EMPTY); ByteArrayOutputStream bs = new ByteArrayOutputStream(); xmlMapper.writerWithDefaultPrettyPrinter().writeValue(bs, student); String xmlString = bs.toString(); System.out.println(xmlString); }