JavaBean 和 XML 相互转换(二)

上一篇文章: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;
}

@XmlElement

标注位置

FIELD, METHOD, PARAMETER

是否必须

非必须

注解作用

JavaBean 属性和 XML 标签相互映射,该注解主要讲解两个属性:

  • name:JavaBean 属性与该属性指定的 XML 标签映射,如果未设置,默认为 JavaBean 属性名称
  • type:当注解标注的属性为接口或父类时,转换时需要指定实现类或子类的类型,否则无法转换

使用该注解的场景一般是 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 号
    
        红色上衣
        绿色裙子
    

@XmlElements

在 @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 数组中,就可以映射

@XmlTransient

标注位置

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)

@XmlAttribute

标注位置

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

标签:长安街   北京市   注解   字段   属性   接口   类型   标签   测试   学生

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top