JAVA beanとXMLが互いに回転する利器---XStream

11407 ワード

最近プロジェクトの中でJAVA beanとXMLの互いに回転する需要に出会って、もともと規則に従ってdom 4 jを使うつもりで突然前に接触したXStreamを思い出して、1回の研究は豁然として明るくて、利器ああ利器、降りてXStreamのいくつかの使い方についてみんなと分かち合います.
XStreamは有名なthought worksの次のオープンソースプロジェクトで、主な機能はJAVA beanとXMLテキスト間の変換を提供することであり、またJAVA beanとJSON間の変換も提供することであり、これは今回の議論の範囲内ではない.
XStreamの変換は非常に簡単で、JAVA beanには何の要求もありません.
  • privateプロパティにaccessメソッド(set/get)を指定する必要はありません.
  • は、デフォルトのコンストラクション関数を提供する必要はありません.

  • 実際のコード操作はもっと簡単で、JAVA 1.5以降XSteamでもannotationがサポートされています.この場合はJAVA BEANにいくつかのannotationを追加すれば良いのですが、もちろんJAVA beanの修正が許されなければXStreamもregisterを提供するのも簡単です.例で示すtopicを用意します.
  • 基本変換
  • オブジェクト別名
  • 処理属性
  • 処理List
  • field
  • を無視
    1.基本変換
    これは普通のJAVA beanです.
    package xstreamTest;
    public class Person {
    	private String name;
    	private int age;
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }
    変換コードは次のとおりです.
    XStream xstream = new XStream();
    Person person = new Person();
    person.setName("pli");
    person.setAge(18);
    System.out.println(xstream.toXML(person));
    私たちはこのような結果を得ました.
    
      pli
      18
    
    

    なぜ「xstreamTest.Person」のラベルがあるのか不思議に思ったことはありませんか?下記のJAVA beanというラベルは、JAVA beanのクラス全パスから来ています.
    しかし、これは私が望んでいるわけではありません.変えられませんか?はい、簡単ですか.簡単!
    2.別名を付ける
    家丁私たちは「xstreamTest.Person」というわけのわからないelementラベルを「person」に変えることを望んでいます.私たちはそうすべきです.
    package xstreamTest;
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	private int age;
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }
    で実行コードは次のようになります.
    XStream xstream = new XStream();
    xstream.autodetectAnnotations(true);
    Person person = new Person();
    person.setName("pli");
    person.setAge(18);
    System.out.println(xstream.toXML(person));

    これで私たちは欲しいものを手に入れました.
    
      pli
      18
    

    ここで言及するのは「xstream.autodetectAnnotations(true);」というコードで、JAVA beanのannotationを解析するためにXstreamに伝えます.このコードには隠れた危険があり、後で議論します.
    別名は、シーケンス化時に変更したいオブジェクトの名前、クラス、属性、パッケージ名を変更することができます.実際には「XSstreamAlias」というannotationが使用されます.
    3.処理属性
    JAVA beanの「age」属性をXMLのpersonタグのattributeとして使用したい場合はどうすればいいでしょうか.
    ここではもう一つのannotation:@XStreamAsAttributeを紹介します.私たちのJAVA beanはこうなりました.
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
        
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    結果は次のとおりです.
    
      pli
    
    は面白いでしょう.
    4.Listの処理
    もしJAVA beanにリストがあったらどうなりますか.
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
    	
    	List girlFriends;
        
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    直接変換すると、次のような結果が得られます.
    
      pli
      
        YuanYuanGao
        QiShu
        BoZhiZhang
      
    
    の結果も悪くないが、XStreamはここで@XStreamImplicit(itemFieldName=***)のannotationを提供し、ユーザーがリストのルートノードをリスト名を削除し、変更したいというニーズを満たすために、私たちの例ではラベルを削除し、「」を変更することに対応している.効果を見てみましょう.
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
    	@XStreamImplicit(itemFieldName="girl")
    	List girlFriends;
        
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    結果は次のとおりです.
    
      pli
      YuanYuanGao
      QiShu
      BoZhiZhang
    

    5.属性を無視
    JAVA beanで一部の属性がシーケンス化されたくない場合、XStreamはこのニーズを解決するannotation:@XStreamOmitFieldを提供します.
    例えばgirlfriendsというリストをシーケンス化したくない
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
    	@XStreamImplicit(itemFieldName="girl")
    	@XStreamOmitField
    	List girlFriends;
        
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    結果は次のとおりです.
    
      pli
    

    6. Converter
    ConverterこれはXStreamの高度な機能であり、基本的な機能が満たされない場合にカスタマイズされたシーケンス化/逆シリーズ化の詳細については、一例で説明します.
    JAVA beanにDateタイプのプロパティを追加する場合は、次の手順に従います.
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
    	@XStreamImplicit(itemFieldName="girl")
    	@XStreamOmitField
    	List girlFriends;
    	Date birthday;
        
    	public Date getBirthday() {
    		return birthday;
    	}
    
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    直接シーケンス化の結果を見てみましょう.
    
      pli
      2012-08-04 04:35:01.857 UTC
    

    いいですね.でも、誕生日は年月日だけでいいです.ミリ秒まで正確にする必要はありません.どうすればいいですか.converterしか使えません.コードを書く必要があります.
    public class DateConverter implements Converter {
    	@Override
    	public boolean canConvert(Class clazz) {
    		return (Date.class).equals(clazz);
    	}
    	@Override
    	public void marshal(Object object, HierarchicalStreamWriter writer,
    			MarshallingContext context) {
    		Date date = (Date) object;
    		Calendar calendar = Calendar.getInstance();
    		calendar.setTime(date);
    		SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
    		writer.setValue(format.format(calendar.getTime()));
    	}
    	@Override
    	public Object unmarshal(HierarchicalStreamReader arg0,
    			UnmarshallingContext arg1) {
    		return null;
    	}
    }

    このコードを少し説明します.DateConverterは言い訳Converterを実現し、インタフェースの3つの方法を実現しました.
  • public boolean canConvert(Class clazz)は、このconverterが入力のタイプを変換できるかどうかを検出するために使用されます.
  • public void marshal(Object object,HierarchicalStreamWriter writer,MarshallingContext context)シーケンス化の方法(JAVA bean-->XML)
  • public Object unmarshal(HierarchicalStreamReader arg0, UnmarshallingContext arg 1)逆シーケンス化の方法.本例は使えないので実現しなかった.

  • 私たちのJAVA beanもそれに応じて変更しなければなりません.
    @XStreamAlias("person")
    public class Person {
    	private String name;
    	@XStreamAsAttribute
    	private int age;
    	@XStreamImplicit(itemFieldName="girl")
    	@XStreamOmitField
    	List girlFriends;
    	@XStreamConverter(value=DateConverter.class)
    	Date birthday;
        
    	public Date getBirthday() {
    		return birthday;
    	}
    
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    結果を見てみましょう.
    
      pli
      2012-50-04
    

    またconverterの原理を簡単に説明します.
    実はXStream変換プロセスは1つのconverterを実行するプロセスで、ただ使用する大部分のconverterはすべて内が建てたので、XStreamは1つの変換するobjectに出会ってまずこのobjectを変換することができる変換器(converter)を探してどのように探して、converterのcanConvert(Class clazz)のこの方法を通じて、trueに戻って変換することができます.分かったでしょう.
    XStreamの制限:
    Xstreamはもういいものですが、本当に足りないものを探すなら、2つあることに気づきました.
    1.逆シーケンス化の場合autodetectAnnotations()メソッドを使用してXStreamオブジェクトにannotationを認識するよう通知できません.
    前のコードのxstream.autodetectAnnotations(true)も覚えています.か、このコードの意味はXStreamオブジェクトにannotationを自動的に認識する必要があることを伝えることで、これはシーケンス化(JAVA bean-->XML)の際に問題ありません.しかし、逆シーケンス化の場合は問題があります.理由は公式サイトで言うのがあいまいで、とにかくだめです.xstream.processAnnotations(Class clazz)で明示的に登録するにはannotationのクラスを使う必要があります.JAVA beanが多いと面倒になります.しかし、一般的にJAVA beanはコード組織構造の中で集中しており、一つのpackageの下に置くと、このpackageの下のJAVA beanをプログラムで取得し、xstream.processAnnotations(Class[]clazzs)を使用して一括登録することもできます.
    2.Null属性はシーケンス化できません.
    前に挙げた例JAVA beanの属性はすべて初期化されてからシーケンス化されていますが、初期化されていなければシーケンス化されたらどうなるのでしょうか、それとも例を挙げますか
    @XStreamAlias("person")
    public class Person {
    	private String name = "pli";
    	@XStreamAsAttribute
    	private int age = 19;
    	@XStreamImplicit(itemFieldName="girl")
    	@XStreamOmitField
    	List girlFriends;
    	@XStreamConverter(value=DateConverter.class)
    	Date birthday = new Date();
        
    	public Date getBirthday() {
    		return birthday;
    	}
    
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    
    	public List getGirlFriends() {
    		return girlFriends;
    	}
    
    	public void setGirlFriends(List girlFriends) {
    		this.girlFriends = girlFriends;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getName() {
    		return this.name;
    	}
    }

    他の属性を初期化したいのですが、girlFriendsという属性を初期化していません.girlFriends=null.シーケンス化したらどうなりますか?
    
      pli
      2012-36-04
    
    girlFriendsという属性はまったくシーケンス化されていませんが、実は私はそれをシーケンス化したいと思っています.
    
      pli
      2012-36-04
      
    

    どうしようもない、しょうがない.私はソースコードを調べて、確かにある属性がnullであればシーケンス化しないで、唯一の方法はソースコードを修正することです.これは手間がかかります.興味があれば、このリンクの文章を参照してください.助けになります.クリックしてリンクを開けてください.
    また、XStreamではannotationが適用されない方法も提供されていますので、興味があればXStreamの公式サイトでご覧ください.
    クリックしてリンクを開く
    はい、たくさん書いてありますが、わかりやすいので、何か質問がありましたら、お知らせください.