上一篇文章:JavaBean 和 XML 相互转换(一)
在上一篇文章中我们介绍了 JavaBean 和 XML 相互转换使用的工具和相关注解(@XmlRootElement、@XmlType、@XmlAccessorType),在本篇文章中继续学习其他相关注解。
本篇测试使用的 JavaBean 同《JavaBean 和 XML 相互转换(一)》,为了方便大家阅读,在本篇冗余之前的代码,如下:
/**
* 学校
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class School {
/**
* 学校名称
*/
private String name;
/**
* 学校联系方式
*/
private String phone;
/**
* 学校地址
*/
private String address;
/**
* 班级
*/
private List classes;
}
/**
* 班级
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ClassInfo {
/**
* 班级编号
*/
private String classNo;
/**
* 班主任
*/
private String teacher;
/**
* 学生
*/
private List students;
}
/**
* 学生
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Student {
/**
* 学号
*/
private String no;
/**
* 学生姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 家庭地址
*/
private String address;
}
标注位置 | FIELD, METHOD, PARAMETER |
是否必须 | 非必须 |
注解作用 | JavaBean 属性和 XML 标签相互映射,该注解主要讲解两个属性:
使用该注解的场景一般是 XML 标签与相应的 JavaBean 属性名称不同,或 JavaBean 属性类型为接口或父类 |
修改学生类,给 address 属性添加注解,其他不变,如下所示:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
// 省略不变的属性
/**
* 家庭地址
*/
@XmlElement(name = "ADDRESS")
private String address;
}
测试代码:
public class XmlBeanMapperTest {
private static final String XML = "<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
" +
"
" +
" 北京市长安街 001 号
" +
" 25
" +
" 张三
" +
" 1001
" +
" ";
/**
* 测试 {@link XmlElement} 注解
*/
@Test
public void testXmlElement() {
Student student = new Student("1001", "张三", 25, "北京市长安街 001 号");
Console.log(JAXBUtil.beanToXml(student));
Console.log(JAXBUtil.xmlToBean(XML, Student.class));
}
}
执行测试代码,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1001
张三
25
北京市长安街 001 号
Student(no=1001, name=张三, age=25, address=null)
通过上面测试结果可以看到,JavaBean 转 XML 后,address 属性对应 XML 的标签为 ADDRESS。反之 XML 字符串中 address 标签也无法映射到 address 属性上。
创建装扮接口 BaseDress:
/**
* 装扮接口
*/
@XmlAccessorType(XmlAccessType.FIELD)
public interface BaseDress {
}
因为在本示例中使用 Lombok @Data 注解,所以需要将注解 @XmlAccessorType value 设置为 FIELD,而且该注解具有继承性(注解使用 @Inherited 元注解),为了不用每个实现类重复添加,所以在接口上统一添加该注解。
修改学生类,添加类型为 BaseDress 的新属性 dress,如下所示:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
// 不变的属性省略
/**
* 装扮
*/
@XmlElement(type = NurseDress.class)
private BaseDress dress;
}
因为 dress 属性的类型是接口,JAXB 无法处理接口类型的属性,所以需要使用 @XmlElement 注解 type 设置对应实现类的类型。这就造成我们无法使用 Java 多态特性。
新增 BaseDress 实现类 NurseDress,如下所示:
/**
* 护士装扮
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class NurseDress implements BaseDress {
/**
* 上衣
*/
private String blouse;
/**
* 裙子
*/
private String skirt;
}
测试代码如下:
public class XmlBeanMapperTest {
/**
* 测试 {@link XmlElement} 注解
*/
@Test
public void testXmlElement() {
Student student = new Student("1001", "张三", 25, "北京市长安街 001 号",
new NurseDress("红色上衣", "绿色裙子"));
Console.log(JAXBUtil.beanToXml(student));
}
}
运行测试类,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1001
张三
25
北京市长安街 001 号
红色上衣
绿色裙子
在 @XmlElement 测试中,有个问题就是如果类的属性类型为接口或抽象类,必须使用 @XmlElement 注解 type 属性指定实现类或子类类型,否则会抛出异常信息。这样不能使用多态,失去了定义接口或抽象类的意义,有一种妥协的方法就是使用 @XmlElements 注解,如下示例。
在 @XmlElement 测试类基础上,新增 BaseDress 实现类 MaidDress,如下所示:
/**
* 女仆装扮
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement(name="jar")
public class MaidDress extends BaseDress {
/**
* 上衣
*/
private String blouse;
/**
* 裙子
*/
private String skirt;
}
修改学生类,修改 dress 属性注解,如下所示:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
// 不变的属性省略
/**
* 装扮
*/
@XmlElements({
@XmlElement(type = NurseDress.class),
@XmlElement(type = MaidDress.class)
})
private BaseDress dress;
}
将 @XmlElement 注解更换为 @XmlElements 注解,并设置其 value 属性为可能赋值的 BaseDress 接口实现类类型数组
运行测试类,测试结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1001
张三
25
北京市长安街 001 号
红色上衣
粉红色裙子
Student(no=1001, name=张三, age=25, address=北京市长安街 001 号, dress=null)
可以正常执行,只要赋值的类型在指定的 @XmlElement 数组中,就可以映射
标注位置 | FIELD, METHOD, TYPE |
是否必须 | 非必须 |
注解作用 | JavaBean 属性和 XML 标签相互映射是忽略标注该注解的属性 |
修改学生类,在 address 属性上添加该注解,如下所示:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
// 不变的属性省略
/**
* 家庭地址
*/
@XmlTransient
private String address;
}
测试类如下:
public class XmlBeanMapperTest {
private static final String XML = "<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
" +
"
" +
" 北京市长安街 001 号
" +
" 25
" +
" 张三
" +
" 1001
" +
" ";
/**
* 测试 {@link XmlTransient} 注解
*/
@Test
public void testXmlTransient() {
Student student = new Student("1001", "张三", 25, "北京市长安街 001 号");
Console.log(JAXBUtil.beanToXml(student));
Console.log(JAXBUtil.xmlToBean(XML, Student.class));
}
}
运行测试类,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1001
张三
25
Student(no=1001, name=张三, age=25, address=null)
标注位置 | FIELD, METHOD |
是否必须 | 非必须 |
注解作用 | 将 JavaBean 的属性与 XML 标签的属性相互映射 |
修改学生类,在 address 属性上添加该注解,如下所示:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
// 不变的属性省略
/**
* 家庭地址
*/
@XmlAttribute
private String address;
}
测试类同 @XmlTransient 注解中的测试类,运行后结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1001
张三
25
Student(no=1001, name=张三, age=25, address=null)
通过上面的结果可以看到学生类 address 属性映射到了 XML student 标签的 address 属性
由于内容较多,其他内容详见下一篇文章,如果文章对大家有所帮助,欢迎点赞、关注、评论。
页面更新:2024-03-07
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号