從 注解和繼承 到 JAXB中的注意事項


從 注解和繼承 到 JAXB中的注意事項

注解在繼承中的行為

如果一個父類添加了一個注解,子類是否能取到這個注解呢?如下

package inheritance;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Main {
	public static void main(String[] args) {
		Type t = Son.class.getAnnotation(Type.class);
		if (t != null) {
			System.out.println(t.name());
		}
	}
}

@Type(name = "Father")
class Father {
}

class Son extends Father {
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Type {
	String name();
}

如上代碼,注解不會被子類繼承。如果想注解也被子類繼承,該怎么辦呢?

只需要在注解定義里修改一下,添加@Inherited

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Type {
	String name();
}

關於@Inherited需要注意的:

  • 只能作用於繼承,不能作用於接口實現

JAXB 的注解

@XmlAccessorType用於標注該類的成員是否用於綁定到XML,例如XmlAccessType.PUBLIC_MEMBER表示,所有public字段都會被綁定(除去@XmlElement和@XmlTransient的標記,他們優先級更高)。
這個注解就是標記了@Inherited。

我們知道序列化順序可以由@XmlType(propOrder)去設置,那么繼承后是什么樣子呢?

package inheritance;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

public class Main {
	public static void main(String[] args) throws Exception {
		JAXBContext ctx = JAXBContext.newInstance(Son.class);
		Marshaller ms = ctx.createMarshaller();
		ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		ms.marshal(new Son(), System.out);
	}
}

@XmlRootElement(name = "Father")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(propOrder = { "two", "one" })
class Father {
	@XmlElement
	private String one = "one";
	@XmlElement
	public String two = "two";
}

@XmlRootElement(name = "Son")
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(propOrder = { "four", "three" })
class Son extends Father {
	@XmlElement
	public String three = "three";
	@XmlElement
	public String four = "four";
}

上述代碼會輸出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Son>
    <two>two</two>
    <one>one</one>
    <four>four</four>
    <three>three</three>
</Son>

父類成員先序列化,再子類成員,順序由各自類的@XmlType設置的順序決定

那么如果子類一定想控制父類成員的序列化順序,而且不同的子類還想各自定義父類成員的序列化順序怎么辦?(CNM, 屁事真多)

好吧,JAXB還是可以滿足這種屁事兒的。

package inheritance;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

public class Main {
	public static void main(String[] args) throws Exception {
		go(Son.class);
		go(Daughter.class);
	}

	private static void go(Class<?> clz) throws Exception {
		JAXBContext ctx = JAXBContext.newInstance(clz);
		Marshaller ms = ctx.createMarshaller();
		ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		ms.marshal(clz.newInstance(), System.out);
	}
}

@XmlTransient
class Father {
	@SuppressWarnings("unused")
	private String one = "one";
	public String two = "two";
}

@XmlRootElement(name = "Son")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(propOrder = { "four", "three", "two" })
class Son extends Father {
	@XmlElement
	public String three = "three";
	@XmlElement
	public String four = "four";
}

@XmlRootElement(name = "Daughter")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { "one", "two", "three", "four" })
class Daughter extends Father {
	@XmlElement
	public String three = "three";
	@XmlElement
	public String four = "four";
}

上述代碼將輸出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Son>
    <four>four</four>
    <three>three</three>
    <two>two</two>
</Son>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Daughter>
    <one>one</one>
    <two>two</two>
    <three>three</three>
    <four>four</four>
</Daughter>

解釋如下:

  • 要想每個子類去控制父類成員,必須把父類標記成@XmlTransient,而且子類@XmlType的propOrder要負責所有自己要序列化的成員
  • 類Son的@XmlAccessorType標注為XmlAccessType.PUBLIC_MEMBER,意味着Son只序列化Public字段。加上父類的public成員,Son共有3個public成員,所以@XmlType(propOrder)寫了三個成員的順序。
  • 類Daughter的@XmlAccessorType標注為XmlAccessType.FIELD,意味着所有父類和自己的成員都會序列化,於是標記四個成員的順序。

忽略dtd

import java.io.FileReader;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

public class Demo2 {

    public static void main(String[] args) throws Exception {

        JAXBContext jc = JAXBContext.newInstance(MyBean.class);

        SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        spf.setFeature("http://xml.org/sax/features/validation", false);
        spf.setNamespaceAware(true);

        XMLReader xmlReader = spf.newSAXParser().getXMLReader();
        InputSource inputSource = new InputSource(
                new FileReader("myfile.xml"));
        SAXSource source = new SAXSource(xmlReader, inputSource);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        MyBean foo = (MyBean) unmarshaller.unmarshal(source);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM