`
234390216
  • 浏览: 10257287 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
A5ee55b9-a463-3d09-9c78-0c0cf33198cd
Oracle基础
浏览量:463818
Ad26f909-6440-35a9-b4e9-9aea825bd38e
springMVC介绍
浏览量:1777879
Ce363057-ae4d-3ee1-bb46-e7b51a722a4b
Mybatis简介
浏览量:1400445
Bdeb91ad-cf8a-3fe9-942a-3710073b4000
Spring整合JMS
浏览量:395575
5cbbde67-7cd5-313c-95c2-4185389601e7
Ehcache简介
浏览量:680875
Cc1c0708-ccc2-3d20-ba47-d40e04440682
Cas简介
浏览量:531810
51592fc3-854c-34f4-9eff-cb82d993ab3a
Spring Securi...
浏览量:1186729
23e1c30e-ef8c-3702-aa3c-e83277ffca91
Spring基础知识
浏览量:471904
4af1c81c-eb9d-365f-b759-07685a32156e
Spring Aop介绍
浏览量:152161
2f926891-9e7a-3ce2-a074-3acb2aaf2584
JAXB简介
浏览量:68824
社区版块
存档分类
最新评论

JAXB(二)——核心注解介绍

    博客分类:
  • JAXB
阅读更多

JAXB核心注解介绍

摘要 本文主要通过理论加实践的方式介绍JAXB非常具有代表性的注解。

XmlRootElement

XmlRootElement用于标注在根节点对应的Java类上。比如上一篇介绍的Person类对应的根节点,我们就在Person类上加上了@XmlRootElement。

@XmlRootElement
public class Person {
//...
    
}

根节点的名称默认会取类名称的首字母小写。如果默认名称不能满足你的需要,可以通过XmlRootElement的name属性指定根节点的名称。比如下面就是需要生成的根节点名称为person1。

@XmlRootElement(name="person1")
public class Person {
//...
    
}

如果需要指定namespace,也可以通过它的namespace属性指定。

XmlElement

XmlElement用于标注Java类的属性或get/set方法上,表示对应的属性或get/set方法需要与XML的某一个元素映射。比如有如下这样一段XML:

<root>
    <value>Hi</value>
</root>

我们需要把它与我们下面的类映射起来,就可以在对应的getAbc()方法上加上@XmlElement(name="value"),其实JAXB注解不是只能加在get方法上,加在set方法上也是可以的,尤其是在只有set方法,没有get方法且只需要将XML转换为对象时,此时如果有需要我们就可以在set方法上加上XmlElement注解了。

@XmlRootElement
public class Root {

    private String abc;
    
    public void setAbc(String abc) {
        this.abc = abc;
    }
    
    @XmlElement(name="value")
    public String getAbc() {
        return this.abc;
    }
    
}

默认情况下一个属性及其对应的get/set方法没有添加任何JAXB注解的时候,该属性也会被自动的与它同名的XML元素进行绑定。所以通常XmlElement用于属性名称与XML元素名称不一致的情况下通过name属性指定需要绑定的XML元素的名称。 除了指定name属性外,我们还可以指定namespace、nilable、required、defaultValue等属性,这些通常用于基于Java类生成对应的XML Schema的情形。

XmlAttribute

XmlAttribute用于映射XML元素属性的,默认的属性名称与Java类的属性名称一致,可以通过name属性指定属性名称。比如下面这个类我们在对应的getNo()方法上加上了@XmlAttribute,表示它将作为Root类对应XML元素上的一个名为no的属性,而getName()上的@XmlAttribute通过name属性指定了它对应的XML属性名是name1。

@XmlRootElement
public class Root {

    private String no;
    
    private String name;
    
    public void setNo(String no) {
        this.no = no;
    }
    
    @XmlAttribute
    public String getNo() {
        return this.no;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @XmlAttribute(name="name1")
    public String getName() {
        return this.name;
    }
    
}

生成的XML是类似如下这样的:

<root name1="AAA" no="A1"/>

除了name属性外,XmlAttribute还可以选择性的指定namespace和required属性。

XmlValue

XmlValue是用于映射直接应用XML元素的文本内容的。比如上面的XML节点root,如果其中还包含有文本内容,如:<root name1="AAA" no="A1">Text Content</root>,我们就可以在Root类中添加一个属性并使用@XmlValue标注,那么该属性的值就对应于root节点的文本内容。

@XmlRootElement
public class Root {

    private String no;
    
    private String name;
    private String value;
    
    public void setNo(String no) {
        this.no = no;
    }
    
    @XmlAttribute
    public String getNo() {
        return this.no;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @XmlAttribute(name="name1")
    public String getName() {
        return this.name;
    }
    
    public void setValue(String value) {
        this.value = value;
    }
    
    @XmlValue
    public String getValue() {
        return this.value;
    }
    
}

XmlType

XmlType用于定义在类上,表示该类对应于XML的一个复杂类型对象。默认情况下不加XmlType时我们的类也会自动的被映射为XML的一个复杂类型对象,对应的XML类型默认是Java类名称的首字母小写的形式,可以如果不需要使用默认名称时可以通过name属性指定。通常我们在一个类上使用@XmlType时主要是希望通过它的propOrder属性指定生成的XML的属性排列顺序,不指定顺序时默认生成的XML的节点/属性的顺序是不确定的。

@XmlRootElement
@XmlType(propOrder= {"no", "name", "value"})
public class Root {

    private String no;
    
    private String name;
    private String value;
    
    public void setNo(String no) {
        this.no = no;
    }
    
    public String getNo() {
        return this.no;
    }
    
    public void setName(String name) {
        this.name = name;
    }

    @XmlElement(name="name1")
    public String getName() {
        return this.name;
    }
    
    public void setValue(String value) {
        this.value = value;
    }
    
    public String getValue() {
        return this.value;
    }
    
}

上面的示例中我们就通过XmlType的propOrder指定了属性的排列顺序为no、name、value,对应的值需要是Java类的属性名。生成的XML是类似如下这样的:

<root>
    <no>A1</no>
    <name1>AAA</name1>
    <value>ABCDEFG</value>
</root>

除了name和propOrder属性外,也可以通过namespace属性指定namespace。如果对应的类型的对象是有某个工厂方法产生的,需要是静态的无参数的方法,我们可以通过factoryClass和factoryMethod指定在进行XML转Java对象创建对应类型的对象的工厂类和工厂方法。

XmlAccessorOrder

XmlAccessorOrder也是指定Java对象生成的XML元素/属性的顺序的。通过它指定的顺序的可选值有:

  • XmlAccessOrder.ALPHABETICAL:按照字母的自然顺序进行升序排列。
  • XmlAccessOrder.UNDEFINED:未定义,即顺序不固定,这个是默认值。

比如上面的排序如果期望是按照字母的自然顺序排列,则可以如下这样定义:

@XmlRootElement
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Root {
    
    //...
    
}

XmlAccessorOrder除了可以定义在类上,还可以定义在包上,定义在包上表示在该包中所有的类型对应的XML的默认排序规则。定义在包中时需要在对应的包下面建立package-info.java文件,然后将该注解加在package-info.java中的package声明上。如下我们就在com.xxx.jaxb的package-info.java中指定了com.xxx.jaxb包中的类对应的XML元素顺序默认按照字母升序排列。

@javax.xml.bind.annotation.XmlAccessorOrder(javax.xml.bind.annotation.XmlAccessOrder.ALPHABETICAL)
package com.xxx.jaxb;

XmlTransient

XmlTransient用于在进行Java对象和XML相互转换时定义需要忽略的Java属性。比如下面的Root类中有no、name和value三个属性,value属性在系统中有其它作用,但是在转换Root对象为XML时我们不期望value属性也作为其中的一部分,就在对应的getValue()方法上加上了@XmlTransient。

@XmlRootElement
public class Root {
    
    private String no;
    private String name;
    private String value;
    
    public void setNo(String no) {
        this.no = no;
    }
    
    public String getNo() {
        return this.no;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return this.name;
    }
    
    public void setValue(String value) {
        this.value = value;
    }
    
    @XmlTransient
    public String getValue() {
        return this.value;
    }
    
}

XmlAccessorType

XmlAccessorType也是JAXB中比较常用的一个注解,可以标注在Class和package上,标注在package上时需要标注在对应的package-info.java文件的package上。XmlAccessorType的作用是指定Java对象和XML相互转换时Java对象属性访问方式,即哪些属性会与XML进行映射。它的可选值是由XmlAccessType类型的枚举指定。一共支持四种类型,无论配置的是哪种类型,使用JAXB注解的都将会自动映射。

  • FIELD:会自动把非static、非transient和非XmlTransient标注的属性与XML进行映射,哪怕对应的属性是私有的。对应的get方法只有在使用了XmlElement等相关注解的情况下才会与XML映射。
  • PROPERTY: 会自动把get/set配对的方法与XML进行映射。使用XmlTransient注解标注的get方法不会自动与XML进行映射,而使用类似于XmlElement这样的注解标注的get方法即使没有对应的set方法也会与XML进行映射。
  • PUBLIC_MEMBER: 这是没有指定XmlAccessorType时的默认映射方式。没有使用XmlTransient标注的public类型的get/set方法对或没有使用transient修饰且没有使用XmlTransient注解标注的public类型的属性将自动与XML进行映射;其它属性或get/set方法如果使用了类似于XmlElement之类的注解进行标注也会自动与XML进行映射。
  • NONE: 不自动将属性和get/set方法与XML进行映射。除非在对应的属性或get/set方法上使用了类似于XmlElement之类的JAXB注解进行标注。

如下代码中我们指定的XmlAccessorType是FIELD,那么在生成XML时就将以Field进行映射,Root类是没有get/set方法的。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    private String no = "no1";
    private String name = "Name1";
    private String value = "Value1";
    
}

生成的XML如下所示:

<root>
    <name>Name1</name>
    <no>no1</no>
    <value>Value1</value>
</root>

如果package和Class上同时拥有XmlAccessorType定义时将以Class上的定义为准。

XmlElementWrapper

XmlElementWrapper用于进行集合类型的属性映射时,在XML元素的外层再多包一层元素。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    private List<String> values = Arrays.asList("A", "B", "C");
    
}

上面这个Java类的对象生成的XML是如下这样:

<root>
    <values>A</values>
    <values>B</values>
    <values>C</values>
</root>

这是因为对于集合类型的属性,JAXB内部会自动遍历其中的每一个元素把它们生成XML,元素的名称默认是属性名称,即上面的values,如果我们希望生成的元素名称是其它的,比如是value,则可以通过@XmlElement(name="value")来指定。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlElement(name="value")
    private List<String> values = Arrays.asList("A", "B", "C");
    
}

这样生成的XML就是如下这样:

<root>
    <value>A</value>
    <value>B</value>
    <value>C</value>
</root>

如果我们希望上面的每一个value元素都可以被一个元素包裹起来,比如values,则可以标注@XmlElementWrapper(name="values"),通过name属性指定包裹的元素的名称,没有指定name属性时包裹的元素的名称默认会取对应的Java属性的名称。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlElementWrapper
    @XmlElement(name="value")
    private List<String> values = Arrays.asList("A", "B", "C");
    
}

加上了@XmlElementWrapper之后生成的XML是如下这样:

<root>
    <items>
        <value>A</value>
        <value>B</value>
        <value>C</value>
    </items>
</root>

XmlElementWrapper除了可以指定name属性外,还可以指定namespace、required和nilable属性。

XmlJavaTypeAdapter

XmlJavaTypeAdapter可以用于在进行Java对象和XML相互转换时做一些适配工作,比如需要把java.util.Date转换为XML的字符串形式的yyyy-MM-dd格式。使用XmlJavaTypeAdapter时需要通过value属性指定一个XmlAdapter类,表示对应的适配器类。XmlAdapter是一个抽象类。其中定义了两个方法,marshal和unmarshal,marshal方法用于适配从Java到XML,unmarshal方法用于适配从XML到Java。比如需要把java.util.Date类型转换为yyyy-MM-dd格式的字符串可以定义如下适配器。

public class DateAdapter extends XmlAdapter<String, java.util.Date> {

    private static final String PATTERN = "yyyy-MM-dd";
    
    @Override
    public Date unmarshal(String v) throws Exception {
        if (v != null) {
            return new SimpleDateFormat(PATTERN).parse(v);
        }
        return null;
    }

    @Override
    public String marshal(Date v) throws Exception {
        if (v != null) {
            return new SimpleDateFormat(PATTERN).format(v);
        }
        return null;
    }

}

适配器实现时注意考虑值为null的情形。

在需要使用适配器的属性或get/set方法上可以通过@XmlJavaTypeAdapter指定需要使用的适配器,比如下面代码就是使用我们刚刚定义的DateAdapter适配器。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date date = new Date();
    
}

生成的XML如下:

<root>
    <date>2017-11-19</date>
</root>

XmlJavaTypeAdapter也可以标注在Java类上,表示遇到对应的类型时就使用指定的适配器,比如下面的代码就会在遇到MyDate类型时自动使用DateAdapter。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    private MyDate date = new MyDate();
    private MyDate date2 = new MyDate();
    
    @XmlJavaTypeAdapter(DateAdapter.class)
    public static class MyDate extends Date {
        
    }
    
}

XmlJavaTypeAdapter也可以标注在package上,标注在package上时必须指定type类型,表示在指定的包中遇到type属性指定的类型时就使用value属性对应的适配器。下面的代码表示在com.xxx.jaxb中遇到java.util.Date类型就使用DateAdapter适配器。

@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value=DateAdapter.class, type=java.util.Date.class)
package com.xxx.jaxb;

XmlJavaTypeAdapters

XmlJavaTypeAdapters只能标注在package上,是用于定义多个XmlJavaTypeAdapters的。比如下面就定义了在包com.xxx.jaxb中遇到了java.util.Date类型就使用DateAdapter适配器,遇到了java.math.BigDecimal类型就使用MoneyAdapter适配器。

@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
        @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = DateAdapter.class, type = java.util.Date.class),
        @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = MoneyAdapter.class, type = java.math.BigDecimal.class) })
package com.xxx.jaxb;

XmlAnyElement

考虑现在有一段XML,其基本结构如下,root是节点下有固定的no和name节点,其它节点不固定,而且可能性很多,穷举非常麻烦。这种场景下我们就可以使用XmlAnyElement来映射了,它可以映射除固定的映射以外的所有其它XML节点。如果需要动态映射的节点确定只有一个,我们可以使用一个Object或org.w3c.dom.Element类型的属性来接收。如果需要动态映射的节点数是不确定的,则需要使用一个List来接收。

<root>
    <no>A01</no>
    <name>A</name>
    <d1>D</d1>
    <d2>D</d2>
</root>

比如上面的示例我们就可以使用一个List来接收,默认创建的都是org.w3c.dom.Element类型的对象。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    public String no;
    public String name;
    @XmlAnyElement
    public List<Object> others;
    
}

如果动态的节点有些是一种固定的类型,我们可以在使用@XmlAnyElement时指定其lax属性为true。这会让JAXB在把XML转换为Java对象时直接把它们转换为对应的对象。比如上面的XML可能出现的d1节点有一个匹配的Java类D1,其代码如下:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    public String no;
    public String name;
    @XmlAnyElement(lax=true)
    public List<Object> others;
    
    @XmlRootElement(name="d1")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class D1 {
        @XmlValue
        public String value;
    }
}

这样进行了unmarshal之后对应的others属性中就包含了一个D1类型的对象了,单元测试如下:

@Test
public void testBasicUnmarshal() throws Exception {
    JAXBContext jaxbContext = JAXBContext.newInstance(Root.class, D1.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Root root = (Root) unmarshaller.unmarshal(this.getClass().getClassLoader().getResourceAsStream("jaxb/dynamic.xml"));
    D1 d1 = null;
    for (Object obj : root.others) {
        if (obj instanceof D1) {
            d1 = (D1) obj;
        }
    }
    Assert.assertNotNull(d1);
}

XmlAnyAttribute

XmlAnyAttribute用于映射除已知属性以外的任意属性,它对应于Java类里面一个Map类型的属性,Map的Key需要是javax.xml.namespace.QName类型的。假设有类似下面这样一段XML需要应用动态的属性匹配。

<holder prop1="value1" prop2="value2" prop3="value3"/>

可以建立类似下面这样的代码进行匹配:

@XmlRootElement(name="holder")
@XmlAccessorType(XmlAccessType.FIELD)
public class AnyAttributeHolder {
    
    @XmlAnyAttribute
    public Map<QName, String> attrs;

}

可以进行验证如下:

@Test
public void test2() {
    String xml = "<holder prop1=\"value1\" prop2=\"value2\" prop3=\"value3\"/>";
    AnyAttributeHolder holder = JAXB.unmarshal(new StringReader(xml), AnyAttributeHolder.class);
    
    Assert.assertTrue(holder.attrs.get(new QName("prop1")).equals("value1"));
    Assert.assertTrue(holder.attrs.get(new QName("prop2")).equals("value2"));
    Assert.assertTrue(holder.attrs.get(new QName("prop3")).equals("value3"));
    
}

XmlElements

XmlElements是用于定义多个@XmlElement的,用于标注在集合类型的属性上以根据集合元素类型给定不同的元素名称。比如下面这段代码我们就定义了集合objs中的String类型的元素对应的XML节点名是string,Integer类型的元素对应的XML节点名是int等。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElementWrapper(name = "objs")
    @XmlElements({ @XmlElement(name = "string", type = String.class), @XmlElement(name = "int", type = Integer.class),
            @XmlElement(name = "boolean", type = Boolean.class), @XmlElement(name = "long", type = Long.class) })
    public List<Object> objs = Arrays.asList("A", 1, true, 1L);
}

上面Root类型的对象转换为XML后会是如下这样的结果:

<root>
    <objs>
        <string>A</string>
        <int>1</int>
        <boolean>true</boolean>
        <long>1</long>
    </objs>
</root>

XmlElementRef

XmlElementRef的用途是在属性定义类型是父类,实际传递值是子类的情况下,以子类的结构生成对应的XML。比如下面示例中Root类有一个Parent类型的属性p,其实际值是子类型Sub的实例。我们在p属性上加上了@XmlElementRef,那么在生成XML时就将以子类型Sub的结构为准。此时子类型上必须加上@XmlRootElement注解,对应的节点名称也将根据子类型上的@XmlRootElement定义的为准。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElementRef
    public Parent p = new Sub();
    
    public static class Parent {
        
        public int p1 = 1;
        
    }
    
    @XmlRootElement
    public static class Sub extends Parent {
        public int s1 = 2;
    }
}

在进行转换时所构建的JAXBContext中必须包含子类型的信息,否则子类型对上下文是未知的,比如下面指定的Root.Sub.class,因为直接根据类Root是没有关联的Sub类的信息的。

@Test
public void testBasicMarshal() throws Exception {
    Root root = new Root();
    JAXBContext jaxbContext = JAXBContext.newInstance(Root.class, Root.Sub.class);
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(root, System.out);
}

上面示例生成的XML如下:

<root>
    <sub>
        <p1>1</p1>
        <s1>2</s1>
    </sub>
</root>

XmlElementRef的另一种用法是引用ObjectFactory中定义的类型,这种用法在后文介绍ObjectFactory时介绍。

XmlElementRefs

XmlElementRefs用于定义多个@XmlElementRef,用于集合属性上。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlElementRefs({@XmlElementRef(type=Parent.class)})
    public List<Object> objs = Arrays.asList(new Sub(), new Sub());
    
    public static class Parent {
        public int p1 = 1;
    }
    
    @XmlRootElement
    public static class Sub extends Parent {
        public int s1 = 2;
    }
    
}

XmlRegistry和XmlElementDecl

XmlRegistry用于标注在充当ObjectFactory角色的类上,ObjectFactory类型的类里面可以定义一些创建某种类型的对象的方法,其上可以使用@XmlElementDecl声明对应的元素定义,方法的返回值需要是JAXBElement类型,定义了该声明的元素可以通过XmlElementRef引用。如下示例中ObjectFactory类中的createUser方法通过@XmlElementDecl(name="userEle")声明了名为userEle的元素定义,其对应JAXBElement的值类型是User类型。Root的user属性通过@XmlElementRef(name="userEle")指定了其关联的是ObjectFactory中name为userEle的@XmlElementDecl声明的元素。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlElementRef(name="userEle")
    public JAXBElement<User> user;
    
    @XmlRegistry
    public static class ObjectFactory {
        
        @XmlElementDecl(name="userEle")
        public JAXBElement<User> createUser(User user) {
            QName qname = new QName("user");
            JAXBElement<User> element = new JAXBElement<>(qname, User.class, user);
            return element;
        }
        
    }
    
    public static class User {
        public String name = "user1";
    }
    
}

使用此种方式在创建JAXBContext时传入的Class需要加入对应的ObjectFactory类。

@Test
public void testBasicMarshal() throws Exception {
    Root root = new Root();
    JAXBContext jaxbContext = JAXBContext.newInstance(Root.class, Root.ObjectFactory.class);
    JAXBElement<User> userEle = new Root.ObjectFactory().createUser(new Root.User());
    root.user = userEle;
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(root, System.out);
}

上述示例生成的XML如下:

<root>
    <user>
        <name>user1</name>
    </user>
</root>

XmlID和XmlIDRef

XmlID用于指定一个类中的某个属性为其唯一标识,对应的属性类型必须是String,且在一个类中只能有一个属性使用@XmlID注解;XmlIDREF用于指定在把一个对象的某个复杂类型的属性转化为XML时,不是直接转换整个对象的结构,而是转换其对应的XmlID。

@XmlAccessorType(XmlAccessType.FIELD)
public static class Product {
    @XmlID
    private String id = "1";
    private String name = "Apple";
}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Order {
    private Integer id = 1;
    @XmlIDREF
    private Product product = new Product();
    private Integer num = 10;
}

上面的java类如果我们把Order对象转换为XML,那么product属性关联的将是对应的Product对象的id属性,而不是整个Product对象。结果如下:

<order>
    <id>1</id>
    <num>10</num>
    <product>1</product>
</order>

XmlList

XmlList用于把基本数据类型的集合对象的内容都生成到一个元素中,每个元素间以逗号分隔。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    @XmlList
    private List<String> strs = Arrays.asList("A", "B", "C");
    
}

比如上面这段配置会生成如下XML:

<root>
    <strs>A B C</strs>
</root>

如果把strs上的@XmlList去掉,则会生成如下XML:

<root>
    <strs>A</strs>
    <strs>B</strs>
    <strs>C</strs>
</root>

XmlSeeAlso

XmlSeeAlso用于指定相关的Class,使其在创建JAXBContext时能够自动被JAXBContext识别。如下示例在创建JAXBContext时只需要传入Root类,其中动态引入到的User类型的对象也能被JAXBContext识别,因为Root类上已经通过@XmlSeeAlso引入了User类。

@XmlRootElement
@XmlSeeAlso(User.class)
public class Root {
    
    public static class User {
        
    }
    
}

XmlEnum和XmlEnumValue

@XmlEnum用于标注在枚举类上,表示其是一个枚举类型。如果你希望生成的Schema中对应的枚举值的定义不是String类型的,则可以通过@XmlEnum的value属性指定类型,比如是int,则可以指定为@XmlEnum(int.class)。@XmlEnumValue用来指定枚举元素值与XML绑定的值。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    
    private Color color = Color.BLUE;
    
    @XmlEnum(int.class)
    public static enum Color {
        @XmlEnumValue("10")
        RED,
        @XmlEnumValue("20")
        BLUE,
        @XmlEnumValue("30")
        YELLOW;
    }
    
}

上面配置的Root类型的对象在转换为XML时会是如下结果,color的值是通过@XmlEnumValue指定的值,而不是枚举元素的字符串表示(默认会是字符串表示)。

<root>
    <color>20</color>
</root>
0
0
分享到:
评论

相关推荐

    ### 【Python图像与PDF文字识别】基于Spire.OCR和Spire.PDF的光学字符识别系统设计:实现图片和扫描PDF中文本的高效提取

    内容概要:本文介绍了如何使用Python识别图片和扫描PDF中的文字。首先,文章讲解了使用Spire.OCR for Python库来识别图片中的文字,包括安装库、配置OCR模型路径和语言设置、扫描图片以及保存识别后的文本。其次,详细描述了从图片中提取文字及其坐标位置的方法,使用户不仅能够获取文本内容,还能知道文本在图片中的具体位置。最后,文章还介绍了如何结合Spire.PDF for Python将PDF文件转换为图片格式,再通过OCR技术从中提取文字,适用于处理扫描版PDF文件。文中提供了完整的代码示例,帮助读者理解和实践。 适合人群:对Python编程有一定基础,希望学习或提高光学字符识别(OCR)技术的应用开发者,尤其是需要处理大量图片或PDF文档中文字信息的工作人员。 使用场景及目标:① 开发者可以利用这些方法自动化处理图片或PDF文档中的文字信息,提高工作效率;② 实现从非结构化数据(如图片、扫描件)到结构化数据(如文本文件)的转换,便于后续的数据分析和处理;③ 提供了一种解决纸质文档数字化的有效途径,特别是对于历史档案、书籍等资料的电子化保存。 其他说明:需要注意的是,OCR的准确性很大程度上取决于图片的质量,清晰度高、对比度好的图片可以获得更好的识别效果。此外,不同OCR库可能对特定语言或字体的支持程度不同,选择合适的库和配置参数能显著提升识别精度。在实际应用中,建议先进行小规模测试,优化参数后再大规模应用。

    2025中小企业数字化转型指南 .pdf

    2025中小企业数字化转型指南

    基于快速多极方法(FMM)和随机低秩近似(RandLRA)的集合卡尔曼滤波器(EnKF)Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    2025-04-10 兜兜\(^o^)/~

    2025-04-10 兜兜\(^o^)/~

    永磁同步电机无位置传感器控制中滑模观测器(SMO)的MATLAB仿真与优化

    内容概要:本文详细介绍了永磁同步电机(PMSM)无位置传感器控制中滑模观测器(SMO)的设计与仿真实现。首先阐述了系统的整体架构,包括速度环和电流环的工作机制。接着深入探讨了滑模观测器的关键实现步骤,如滑模增益选择、符号函数的应用以及低通滤波器的作用。文中还涉及了坐标变换(Clarke变换和Park变换)、PI参数整定、SVPWM调制等重要环节的具体实现方法和技术难点。此外,作者分享了多个调试过程中遇到的问题及解决方案,如波形抖振、电流采样延时、扇区判断错误等。最后展示了仿真结果,证明了所提方案的有效性和可行性。 适合人群:从事电机控制系统研究与开发的技术人员,尤其是对无位置传感器控制感兴趣的工程师。 使用场景及目标:适用于希望深入了解并掌握永磁同步电机无位置传感器控制技术的研究人员和工程师。目标是帮助读者理解滑模观测器的工作原理,掌握其设计与调试技巧,从而应用于实际项目中。 其他说明:文中提供了丰富的代码片段和实践经验,有助于读者更好地理解和应用理论知识。同时提醒读者注意离散化步长的选择和滑模增益的调整,这些都是确保系统稳定运行的重要因素。

    航天器姿态控制中时变滑模自适应控制及其MATLAB实现

    内容概要:本文详细介绍了航天器姿态控制中的关键技术,包括时变滑模控制、自适应控制、执行器饱和处理及推力器安装偏差补偿。针对航天器在复杂环境中面临的不确定性,提出了时变滑模面设计、自适应参数更新、饱和控制和安装偏差补偿的具体实现方法,并提供了相应的MATLAB代码。通过合理的控制策略设计,确保航天器在面对多种干扰因素时仍能保持高精度的姿态控制。 适合人群:航空航天领域的研究人员、控制系统工程师、高校相关专业师生。 使用场景及目标:适用于航天器姿态控制系统的开发与优化,旨在提升系统的鲁棒性、稳定性和控制精度。具体应用场景包括卫星姿态调整、深空探测器姿态控制等。 其他说明:文中提供的MATLAB代码可以直接用于实验验证和教学演示,帮助读者深入理解各控制环节的工作原理和技术细节。此外,文中还分享了许多实用的工程经验,如参数整定技巧、常见问题处理等,有助于指导实际项目开发。

    四轮转向汽车MPC路径跟踪:Simulink-Simscape仿真实现与优化

    内容概要:本文详细介绍了基于Simulink-Simscape平台构建的四轮转向汽车模型预测控制(MPC)路径跟踪系统。首先,文章阐述了车辆动力学模型的核心结构,包括前轮和后轮转向角的计算方法以及魔术轮胎模型的配置。接着,深入探讨了MPC控制器的设计,特别是代价函数的配置和QP优化的具体实现。此外,还讨论了路面切换模块的设计,确保不同路况下的稳定性和响应性。最后,文章分享了一些调参经验和仿真参数设置的技巧,如积分限幅、随机质量块的应用以及解算器的选择。 适合人群:从事自动驾驶、车辆控制系统研究的工程师和技术人员,尤其是对路径跟踪算法和MPC有浓厚兴趣的研究者。 使用场景及目标:适用于开发和优化四轮转向汽车的路径跟踪系统,旨在提高车辆在各种复杂路况下的行驶稳定性和精确度。具体目标包括减小方向盘转角误差、控制横向位移偏差、优化轮胎力计算等。 其他说明:文中提供了大量MATLAB代码片段和具体的参数配置,帮助读者更好地理解和复现实验结果。同时,作者分享了许多实际调试过程中遇到的问题及其解决方案,使读者能够避开常见陷阱并高效完成模型搭建。

    全国银行代码和支行代城市地区mysql

    全国银行代码和支行代城市地区mysql

    自动驾驶路径规划:基于MATLAB/SIMULINK的动态规划实现动态避障功能

    内容概要:本文详细介绍了如何利用动态规划(Dynamic Programming, DP)在MATLAB/SIMULINK环境中实现自动驾驶车辆的动态避障功能。首先,文章解释了动态规划的核心思想及其在路径规划中的应用,特别是通过状态转移方程来解决避障问题。接着,讨论了运动学模型(如自行车模型)的建立方法,以及如何通过PID和MPC控制算法进行路径跟踪和避障。此外,文章还探讨了联合仿真平台(MATLAB + Carsim + Prescan)的搭建和配置,展示了如何将理论转化为实际的仿真效果。最后,提供了完整的代码实现和调试技巧,帮助读者快速上手并优化性能。 适合人群:对自动驾驶技术和路径规划感兴趣的科研人员、工程师和技术爱好者。 使用场景及目标:适用于研究和开发自动驾驶系统,特别是在复杂环境下实现高效的动态避障功能。目标是提高车辆的安全性和智能化水平,减少人为干预。 其他说明:文中提供的代码已在GitHub上开源,读者可以直接下载并运行。需要注意的是,某些高级功能(如深度强化学习)将在后续版本中继续探索。

    【Python面试】拼多多Python面试题目解析:涵盖选择题、填空题、编程题及高并发秒杀系统设计列出了拼多多Python

    内容概要:本文档是《拼多多Python面试题目.pdf》,涵盖了Python编程语言的面试题目及其参考答案。文档分为四个主要部分:选择题、填空题、代码编程题和综合题。选择题涉及Python基础知识、多线程、Redis使用场景、字符编码转换、协程特性、深拷贝操作等;填空题考察了列表推导式、对象序列化、文件操作、字符串处理等知识点;代码编程题包括统计热门商品、订单时间窗口校验、字符串压缩、异步批量请求、最长递增子序列等实际编程任务;综合题则要求设计一个高并发秒杀系统,涵盖缓存、数据库、消息队列的选择,库存扣减、分布式锁、限流策略等关键模块的实现思路,以及解决缓存相关问题的方法。 适合人群:有一定Python编程基础,准备求职或希望提升技术能力的开发者,尤其是对Python高级特性和实际应用感兴趣的工程师。 使用场景及目标:①帮助面试者熟悉Python常见知识点和技巧,提高面试成功率;②通过实际编程题目的练习,加深对Python语法和标准库的理解;③掌握高并发系统的架构设计思路,培养解决复杂业务问题的能力。 阅读建议:此文档不仅包含理论知识的选择题和填空题,还有实际编程题目的训练,建议读者在学习过程中不仅要关注正确答案,更要理解每个选项背后的原理,同时动手实践编程题目,结合实际案例进行思考和总结。

    【Java算法面试】涵盖JVM、数据结构与并发编程的面试题汇总及无人机控制系统设计

    内容概要:本文档《Java 算法面试题目.pdf》涵盖了 Java 编程语言的核心知识点和常见面试题,分为选择题、填空题、代码编程题和综合题四个部分。选择题涉及 Java 内存模型、字符串处理、集合类、垃圾回收、线程池、设计模式、Spring 事务、流操作、类加载机制、锁机制、Netty 和 Redis 持久化等主题。填空题考察了线程同步、HashMap 负载因子、序列化、数学运算、Spring 注入、字符串对象创建、位移运算、字符串方法、动态代理和 JVM 参数配置等细节。代码编程题要求实现链表反转、线程安全单例模式、快速排序、二叉树层序遍历和 LRU 缓存等功能。综合题则要求设计一个无人机实时控制系统,涵盖并发控制、可靠传输、路径规划、高可用性和低延迟等方面。; 适合人群:具有 Java 编程基础,尤其是准备面试的中高级开发人员,以及对 Java 核心技术和框架有深入理解需求的技术人员。; 使用场景及目标:①帮助开发者复习和巩固 Java 基础知识和常见面试考点;②通过编程题提升实际编码能力;③通过综合题锻炼系统设计和架构思维,掌握分布式系统的设计要点。; 阅读建议:建议读者先复习相关知识点,再尝试解答题目,最后对照参考答案进行查漏补缺。对于综合题,应结合实际项目经验思考解决方案,重点理解系统设计的关键点和技术选型的理由。

    机械工程基于专利CN112302938A的节能高效双螺杆压缩机转子型线设计与实现:动力传动与控制技术领域非对称齿面组合型线系统开发(论文复现或解答,含详细代码及解释)

    内容概要:该专利提出了一种节能高效的双螺杆压缩机转子型线设计方案,属于动力传动与控制技术领域。核心创新点在于阴阳转子的齿曲线采用抛物线、圆弧、椭圆及其共轭包络线组合而成,形成二次曲线与二次曲线包络线的组合型线。设计特点包括非对称齿面(前齿面更宽,b/a>1.8)、各段曲线光滑连接无尖点、七段曲线组合结构。该设计旨在提高密封性、改善动力特性、降低损耗、提升效率,从而提高双螺杆压缩机的整体性能。文中提供了详细的Python代码实现,包括转子型线的计算和可视化,以及改进后的代码,以更好地反映专利的具体参数和技术细节。 适合人群:机械工程专业人员、从事压缩机设计与制造的技术人员、对双螺杆压缩机转子型线设计感兴趣的科研人员。 使用场景及目标:①用于研究和开发新型双螺杆压缩机,特别是在提高压缩机效率和性能方面;②作为教学案例,帮助学生和工程师理解双螺杆压缩机转子型线的设计原理和技术实现;③为企业提供参考,优化现有产品的设计和制造工艺。 其他说明:文中提供的代码基于专利描述进行了合理的假设和简化,实际应用中可能需要根据具体性能要求进行优化调整。专利技术通过非对称设计、多段曲线组合等方式,实现了高效的密封性和优良的动力特性,显著提升了双螺杆压缩机的性能。

    基于PFC3D5.0的滑坡冲击建筑物仿真与易损性分析代码解析

    内容概要:本文详细介绍了利用PFC3D5.0进行滑坡冲击建筑物仿真的全流程,涵盖滑坡体和建筑物的建模、参数设定、监测系统的构建以及灾后损伤评估。文中不仅提供了完整的Python代码示例,还解释了各个关键参数的选择依据及其对仿真结果的影响。通过实例展示了如何设置滑坡体的尺寸、密度、阻尼系数等属性,以及建筑物的材料属性、粘结强度等参数。同时,文章强调了实时监测系统的重要性,包括冲击力传感器的布置和预警机制的设计。此外,还探讨了不同条件下建筑物的易损性曲线生成方法及其应用价值。 适合人群:从事地质灾害研究、结构工程分析的专业人士,尤其是那些希望深入了解滑坡冲击建筑物过程并掌握相关数值模拟技术的研究人员和技术人员。 使用场景及目标:适用于需要进行滑坡灾害风险评估、建筑设计优化以及应急响应规划的项目。主要目标是帮助用户理解和预测滑坡对建筑物造成的潜在损害,从而提高建筑物的安全性和耐久性。 其他说明:文中提供的代码和参数设置均经过多次实验验证,确保了较高的准确性。对于想要进一步探索这一领域的读者来说,本文提供了一条从理论到实践的学习路径。

    1月最新修复版影视投资理财程序+支付对接+带完整教程

    修复版本,改了短信接口到阿里云,现在好像国内短信接口管的最松的反而是阿里了,支付也已经接好了派特了。可以直接开户直接用了,带非常非常非常完整的搭建教程,萌新都可以随便装起来了。

    自动驾驶领域中基于Matlab/Simulink与Carsim的ACC巡航控制分层PID控制模型构建及应用

    内容概要:本文探讨了在自动驾驶领域中,利用Matlab/Simulink 2018b和Carsim 2020构建ACC(自适应巡航控制)系统的分层PID控制模型的方法和技术要点。首先介绍了软件选择的原因及其版本要求,强调了版本兼容性的重要性。接着详细讲解了模块化建模方法的应用,包括单独的Carsim配置文件、电机驱动模块、车辆巡航模块、车辆跟踪模块、切换逻辑、速度跟踪模块以及联合仿真模块等七个关键组成部分的作用和实现方式。文中提供了具体的MATLAB代码片段展示上层和下层PID控制器的工作机制,并分享了一些实用的小技巧,如安全距离动态补偿、积分限幅处理、死区设置等。此外,还讨论了联合仿真的注意事项,如接口版本匹配、远程调试设置等问题。最后提到模型验证的有效测试案例,并指出整套源码中最值得关注的部分是状态机实现。 适合人群:对自动驾驶技术感兴趣的科研人员、工程师以及相关专业的学生,尤其是那些希望深入了解ACC系统内部工作机制的人群。 使用场景及目标:①帮助读者掌握如何使用Matlab/Simulink和Carsim建立并优化ACC巡航控制系统;②提高读者对PID控制理论的理解及其在实际工程项目中的应用能力;③为从事智能交通系统研究的专业人士提供有价值的参考资料。 其他说明:本文不仅涵盖了理论知识,还包括大量实践经验分享,有助于初学者快速入门的同时也为资深从业者带来新的思考角度。

    基于西门子1200博图V16的五层电梯仿真系统:无硬件依赖的高效教学与验证工具

    内容概要:本文详细介绍了基于西门子S7-1200 PLC和TIA Portal V16平台的五层电梯仿真系统。该系统利用博图V16的仿真环境,无需实体PLC即可实现电梯的动态动画运行。核心内容涵盖PLC程序的状态机设计、呼叫处理模块、HMI组态画面的设计以及安全回路处理等方面。文中展示了具体的代码片段,如电梯状态机的嵌套状态切换逻辑、呼叫信号的位操作处理、HMI动画的位置计算等。此外,还提到了一些实用技巧,如优化响应速度的方法、动画效果的实现细节以及仿真过程中可能遇到的问题及其解决方案。 适合人群:工控领域的工程师、培训讲师、学生及其他对电梯控制系统感兴趣的人员。 使用场景及目标:①作为教学工具,帮助学员理解和掌握电梯控制系统的逻辑设计;②作为验证工具,用于测试和优化电梯控制系统的性能;③为实际工程项目提供参考,减少硬件调试的时间和成本。 其他说明:该仿真系统不仅提供了完整的PLC程序和HMI项目文件,还包括详细的仿真参数配置指南和故障模拟功能,使得教学和实验更加生动有趣。

    基于GPDK45nm工艺的Bandgap带隙基准电路仿真与优化指南

    内容概要:本文详细介绍了Bandgap带隙基准电路的设计、仿真及其优化技巧。首先解释了启动电路的重要性和具体实现方式,确保电路能够稳定启动。接着深入探讨了如何通过仿真工具(如Cadence、Spectre等)进行抛物线曲线、电源抑制比(PSR)、稳定性等方面的仿真测试。提供了具体的Verilog、TCL和Spectre代码片段,帮助读者理解和实践这些复杂的电路特性。此外,还分享了一些实用的经验和技巧,如如何调整电阻比例、设置合适的仿真参数、处理潜在的振荡问题等。 适合人群:具有一定模拟电路基础知识的工程师和技术爱好者,尤其是对Bandgap带隙基准电路感兴趣的读者。 使用场景及目标:适用于希望深入了解Bandgap带隙基准电路的工作原理并掌握其仿真方法的人群。目标是在实践中提高电路设计能力,解决实际工程中的问题。 其他说明:文中不仅提供了理论知识,还包括大量实际操作步骤和代码示例,使读者能够在动手实践中加深理解。同时,强调了在GPDK45nm工艺下的特殊注意事项,为从事先进工艺电路设计的研究人员提供宝贵参考资料。

    人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明

    人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTorch实现高分遥感语义分割(地物分类)项目源码+文档说明人工智能-遥感-语义分割-PyTo

    路宁-驾驭大模型开发真实项目代码.pdf

    路宁-驾驭大模型开发真实项目代码.pdf

    包装类型.md

    包装类型.md

Global site tag (gtag.js) - Google Analytics