zoukankan      html  css  js  c++  java
  • JAXB:java对象和xml之间转换

    JAXB(Java Architecture for XML Binding)是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。

    常用注解:

    @XmlRootElement:将类映射为根元素

    该注解含有name和namespace两个属性。namespace属性用于指定生成的元素所属的命名空间。name属性用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名。

    @XmlElement:将被注解的字段映射为子元素。

    name属性可以指定生成元素的名字

    @XmlAttribute:将字段映射成本类对应元素(标签)的属性

    @XmlTransient:在映射xml元素时忽略被注解的字段

    @XmlAccessorType:决定哪些字段会被映射为xml元素。

      XmlAccessType.FIELD:java对象中的所有成员变量

      XmlAccessType.PROPERTY:java对象中所有通过getter/setter方式访问的成员变量(属性)

      XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量

      XmlAccessType.NONE:java对象的所有属性都不映射为xml的元素

    @XmlElementWrapper:用在集合对象上,映射后包装同一个元素。此时@XmlElement可以没有。

    @XmlJavaTypeAdapter:指定自定义适配器,解决java日期(Date),数字(Number)格式化问题。

    实例:

    实体类

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)  # 表示成员变量就可以被转换成xml中的标签
    public class Boy {
        public String name = "CY";
    }

    测试类

    public class JAXBTest {
        public static void main(String[] args) throws JAXBException {
            JAXBContext context = JAXBContext.newInstance(Boy.class);
    
            Marshaller marshaller = context.createMarshaller();
            Unmarshaller unmarshaller = context.createUnmarshaller();
         // marshall将java对象转成xml
            Boy boy = new Boy();
            marshaller.marshal(boy, System.out);
            System.out.println();
         // unmarshall将xml转成java对象
            String xml = "<boy><name>David</name></boy>";
            Boy boy2 = (Boy) unmarshaller.unmarshal(new StringReader(xml));
            System.out.println(boy2.name);
    
        }
    }

    结果:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>
    David

    改造一:

    将XmlAccessType.FIELD改为XmlAccessType.PROPERTY

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.PROPERTY)  # 只有属性才能转换成xml中的标签
    public class Boy {
        public String name = "CY";
    }

    再次运行,结果为:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy/>
    CY

    发现Marshall和unMarshall都失败。由于name没有getter/setter方法,故不是属性,所以java对象转成xml时,name不转为标签

    该造二:

    给name属性添加 get set 方法。

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        public String name = "CY";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    再次执行,结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>
    David

    结果正常

    改造三:

    给Boy 再添加一个field, int age=10

    再次运行,结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><name>CY</name></boy>
    David

    显然,这个age 是不会被 转化 到xml 文件中的。解决办法是:给age添加@XmlElement注解

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        public String name = "CY";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        @XmlElement
        int age=10;
    }

    再次运行,结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><boy><age>10</age><name>CY</name></boy>
    David

    发现多了一个age标签

    使用@XmlElement注解,成员变量可以映射为标签,

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        @XmlElement
        public String name = "CY";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        @XmlElement
        int age=10;
    }

    但是属性不能加@XmlElement注解,否则报错如下:

    Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
    类的两个属性具有相同名称 "name"
        this problem is related to the following location:
            at public java.lang.String com.ljxx.entity.business.Boy.getName()
            at com.ljxx.entity.business.Boy
        this problem is related to the following location:
            at public java.lang.String com.ljxx.entity.business.Boy.name
            at com.ljxx.entity.business.Boy
    
        at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)
        at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:460)
        at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:292)
        at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:139)
        at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1138)
        at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:162)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)
        at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)
        at javax.xml.bind.ContextFinder.find(ContextFinder.java:441)
        at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
        at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
        at com.ljxx.JAXBTest.main(JAXBTest.java:18)

    改造四:

    将@XmlRootElement改为@XmlRootElement(name="b" nameSpace="http://test"),

    @XmlRootElement(name="b",namespace ="http://test")
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        public String name = "CY";
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        @XmlElement
        int age=10;
    }

    测试类

    public class JAXBTest {
        public static void main(String[] args) throws JAXBException {
            JAXBContext context = JAXBContext.newInstance(Boy.class);
    
            Marshaller marshaller = context.createMarshaller();
            Unmarshaller unmarshaller = context.createUnmarshaller();
    
            Boy boy = new Boy();
            marshaller.marshal(boy, System.out);
            System.out.println();
    
        }
    }

    再次运行,结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:b xmlns:ns2="http://test"><age>10</age><name>CY</name></ns2:b>

    在生成的xml文件中,<boy> 标签 就会变为 <b> 标签。并且加上一个命名空间。

    如果不加名称空间:@XmlRootElement(name="b"),结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><b><age>10</age><name>CY</name></b>

    发现<boy> 标签 就会变为 <b> 标签

    改造五:

    如果不使用@XmlAccessorType指定,@XmlAccessorType的默认访问级别是XmlAccessType.PUBLIC_MEMBER,

    @XmlRootElement(name="b")
    public class Boy {
        public String name = "CY"; # public访问权限的成员变量
    
        @XmlElement
        int age=10;
    }

    @XmlRootElement(name="b")
    public class Boy {
        private String name = "CY";
      // 由于name被private修饰,故只能通过getter/setter方式访问的成员变量
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @XmlElement
        int age=10;
    }

    结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><b><name>CY</name><age>10</age></b>

    当为XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量都可以转为标签。

    改造六:

    XmlAccessType.PROPERTY:表明只能是属性才能被转为xml中的元素,而@XmlAttribute注解将成员变量映射为属性

    @XmlRootElement(name="b")
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        @XmlAttribute
        private String name = "CY";
    
        @XmlElement
        int age=10;
    }

    结果:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><b name="CY"><age>10</age></b>

    发现name成员变量变为了标签的属性

    改造七:

    @XmlTransient注解忽略被注解的字段

    @XmlRootElement(name="b")
    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class Boy {
        @XmlAttribute
        private String name = "CY";
    
        @XmlTransient
        int age=10;
    }

    结果:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><b name="CY"/>

    改造八:

    添加一个Key类

    @XmlRootElement
    public class Key {
        @XmlElement
        private String roomNo;
    
        public Key() {
        }
    
        public Key(String roomNo) {
            this.roomNo = roomNo;
        }
    }

    修改Boy类如下:

    @XmlRootElement(name="b")
    public class Boy {
        @XmlElement
        private String name;
    
        @XmlElement
        int age;
    
        public Boy() {
        }
        @XmlElement
        private Set<Key> key = new HashSet<>();
    
        public Boy(String name, int age) {
            this.name = name;
            this.age = age;
            key.add(new Key("001"));    //向集合中添加两个Key对象
            key.add(new Key("002"));
    
        }
    }

    修改测试类如下:

    public class JAXBTest {
        public static void main(String[] args) throws JAXBException {
            JAXBContext context = JAXBContext.newInstance(Boy.class);
    
            Marshaller marshaller = context.createMarshaller();
            Unmarshaller unmarshaller = context.createUnmarshaller();
    
            Boy boy = new Boy("CY",10);
            marshaller.marshal(boy, System.out);
            System.out.println();
    
        }
    }

    当不加@XmlElementWrapper(name="keys")注解时,结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <b>
        <name>CY</name>
        <age>10</age>
        <key>
            <roomNo>001</roomNo>
        </key>
        <key>
            <roomNo>002</roomNo>
        </key>
    </b>

    当加上@XmlElementWrapper(name="keys")后代码如下:

    @XmlRootElement(name="b")
    public class Boy {
        @XmlElement
        private String name;
    
        @XmlElement
        int age;
    
        public Boy() {
        }
        @XmlElementWrapper(name="keys")
        @XmlElement
        private Set<Key> key = new HashSet<>();
    
        public Boy(String name, int age) {
            this.name = name;
            this.age = age;
            key.add(new Key("001"));    //向集合中添加两个Key对象
            key.add(new Key("002"));
    
        }
    }

    结果为:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <b>
        <name>CY</name>
        <age>10</age>
        <keys>
            <key>
                <roomNo>001</roomNo>
            </key>
            <key>
                <roomNo>002</roomNo>
            </key>
        </keys>
    </b>

    改造九:

    在Boy类中添加一个Date类型字段

    @XmlRootElement(name="b")
    public class Boy {
        @XmlElement
        private String name;
    
        @XmlElement
        int age;
        @XmlElement
        private Date date = new Date();
    
        public Boy() {
        }
        @XmlElementWrapper(name="keys")
    //    @XmlElement
        private Set<Key> key = new HashSet<>();
    
        public Boy(String name, int age) {
            this.name = name;
            this.age = age;
            key.add(new Key("001"));    //向集合中添加两个Key对象
            key.add(new Key("002"));
    
        }
    }

    结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <b>
        <name>CY</name>
        <age>10</age>
        <date>2021-09-27T17:26:41.525+08:00</date>
        <keys>
            <key>
                <roomNo>001</roomNo>
            </key>
            <key>
                <roomNo>002</roomNo>
            </key>
        </keys>
    </b>

    我们需要yyyy-MM-dd格式的日期,这就需要@XmlJavaTypeAdapter注解,自定义一个适配器来解决这个问题。

    自定义适配器继承XmlAdapter类,实现里面的marshal和unmarshal方法

    public class DateAdapter extends XmlAdapter<String, Date> {
        private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
        @Override
        public Date unmarshal(String date) throws Exception {
            return SDF.parse(date);
        }
    
        @Override
        public String marshal(Date date) throws Exception {
            return SDF.format(date);
        }
    }

    添加@XmlJavaTypeAdapter(DateAdapter.class)

    @XmlRootElement(name="b")
    public class Boy {
        @XmlElement
        private String name;
    
        @XmlElement
        int age;
        @XmlElement
        @XmlJavaTypeAdapter(DateAdapter.class)
        private Date date = new Date();
    
        public Boy() {
        }
        @XmlElementWrapper(name="keys")
    //    @XmlElement
        private Set<Key> key = new HashSet<>();  // key即为被keys标签包装的标签的名字
    
        public Boy(String name, int age) {
            this.name = name;
            this.age = age;
            key.add(new Key("001"));    //向集合中添加两个Key对象
            key.add(new Key("002"));
    
        }
    }

    结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <b>
        <name>CY</name>
        <age>10</age>
        <date>2021-09-27</date>
        <keys>
            <key>
                <roomNo>001</roomNo>
            </key>
            <key>
                <roomNo>002</roomNo>
            </key>
        </keys>
    </b>

     改造十:

    设置输出的格式:换行和缩进  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

    public class JAXBTest {
        public static void main(String[] args) throws JAXBException {
            JAXBContext context = JAXBContext.newInstance(Boy.class);
    
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    
            Boy boy = new Boy("CY",10);
            marshaller.marshal(boy, System.out);
            System.out.println();
        }
    }

    结果如下:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <b>
        <name>CY</name>
        <age>10</age>
        <date>2021-09-27</date>
        <keys>
            <key1>
                <roomNo>001</roomNo>
            </key1>
            <key1>
                <roomNo>002</roomNo>
            </key1>
        </keys>
    </b>

     改造十一:

    去掉生成xml时的默认报文头:marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

    public class JAXBTest {
        public static void main(String[] args) throws JAXBException {
            JAXBContext context = JAXBContext.newInstance(Boy.class);
    
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
    
            Boy boy = new Boy("CY",10);
            marshaller.marshal(boy, System.out);
            System.out.println();
        }
    }

    结果如下:

    <b>
        <name>CY</name>
        <age>10</age>
        <date>2021-09-27</date>
        <keys>
            <key1>
                <roomNo>001</roomNo>
            </key1>
            <key1>
                <roomNo>002</roomNo>
            </key1>
        </keys>
    </b>
  • 相关阅读:
    HTML-代码定义
    数组
    for。。。for嵌套if,if嵌套for。
    输入年月日, 判断输入的是否正确
    日期功能
    方程
    5.8 一维数组
    5.9 二维数组
    5.7 类
    5.4穷举,迭代
  • 原文地址:https://www.cnblogs.com/zwh0910/p/15343181.html
Copyright © 2011-2022 走看看