EasyJF 官方网站全面升级,同时EasyJF开源团队也将进行全面改组,期待您给我们提出宝贵的意见及建议!

当前位置:首页-技术前沿-其它开源框架

  • XStream Annotations 入门【翻译】
    作者: stef_wu  来源:easyjf  发布时间:2007-11-26 09:28:00
  • 1,问题:
    有的时候,过多的调用XStream的别名(aliases)和转化器(converter)方法来定制您的XStream会是很难看的,你或许会希望使用java annotations来配置POJO,该入门指南介绍XStream提供的一些用于配置XStream的annotations。首先来看一个Message类:

    package com.thoughtworks.xstream; 
    package com.thoughtworks.xstream; 
    public class RendezvousMessage {  
     private int messageType;   
     public RendezvousMessage(int messageType) { 
      this.messageType = messageType; 
     }   
    }

     接着使用XStream来创建我们的XML文件:

    package com.thoughtworks.xstream; 
    public class Tutorial {   
     public static void main(String[] args) { 
      XStream stream = new XStream(new DomDriver()); 
      RendezvousMessage msg = new RendezvousMessage(15); 
      System.out.println(stream.toXML(msg)); 
     } 
    }

    我们得到类似于下面的XML结果:

    <com.thoughtworks.xstream.RendezvousMessage> 
      <messageType>15</messageType> 
    </com.thoughtworks.xstream.RendezvousMessage>

    别名annotations:
    最常用的annotation是为类型和属性创建别名的标签:@XStreamAlias。下面是使用该标签注释我们的类型和属性:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType; 
      
     public RendezvousMessage(int messageType) { 
      this.messageType = messageType; 
     }  
    }

    下面的操作过程比较奇特,我们需要告诉XStream去从这个类型中读出annotation。这个操作和annotation本身的机制有关,你必须告诉XStream主动去解析annotation:

    public static void main(String[] args) {
      XStream stream = new XStream(new DomDriver());
      Annotations.configureAliases(stream, RendezvousMessage.class);
      RendezvousMessage msg = new RendezvousMessage(15);
      System.out.println(stream.toXML(msg));
     }

     注意我们调用了Annotation类的configureAliases静态方法。这个方法首先把XStream中的所有的别名annotations注册到第一个参数中,这个方法使用的是可变参数方法,可以一次性的注册多个类型。下面是我们期望的输出:

    <message>
      <type>15</type>
    </message>

    3,去掉collections标记:
    下面我们为RendezvousMessage添加一个List类型属性content,并使用annotations来实现implicit collections相同的功能:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType;         
     private List<String> content; 
      public RendezvousMessage(int messageType, String ... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    } 
    
    public static void main(String[] args) { 
      XStream stream = new XStream(new DomDriver()); 
      Annotations.configureAliases(stream, RendezvousMessage.class); 
      RendezvousMessage msg = new RendezvousMessage(15, "firstPart","secondPart"); 
      System.out.println(stream.toXML(msg)); 
     }

     输出的结果:

    <message> 
      <type>15</type> 
      <content class="java.util.Arrays$ArrayList"> 
        <a class="string-array"> 
          <string>firstPart</string> 
          <string>secondPart</string> 
        </a> 
      </content> 
    </message>

    这并不是我们想要的结果,现在面我们就使用标签来取消content列表的collection属性名:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType; 
     @XStreamImplicit 
     private List<String> content; 
     public RendezvousMessage(int messageType, String... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    }

    下面是输出的结果:

    <message> 
      <type>15</type> 
      <a class="string-array"> 
        <string>firstPart</string> 
        <string>secondPart</string> 
      </a> 
    </message>

    已经接近了,下一步,希望移除a标记,并使用part来标记各个content。为了到达这个目的,我们使用lmplicit collections标签的另一个属性,这个属性创建了一个collection中每一个数据的tag名字:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType; 
     @XStreamImplicit(itemFieldName="part") 
     private List<String> content; 
     public RendezvousMessage(int messageType, String... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    }

    我们得到下面的结果:

    <message> 
      <type>15</type> 
      <part>firstPart</part> 
      <part>secondPart</part> 
    </message>

     5,自定义转换器:
    下面我们创建另一个属性,用来定义一个message创建的timestamp:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType; 
     @XStreamImplicit(itemFieldName="part") 
     private List<String> content; 
     private Calendar created = new GregorianCalendar(); 
     public RendezvousMessage(int messageType, String... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    }

    得到下面的xml:

    <message> 
      <type>15</type> 
      <part>firstPart</part> 
      <part>secondPart</part> 
      <created> 
        <time>1154097812245</time> 
        <timezone>America/Sao_Paulo</timezone> 
      </created> 
    </message>

    下面我们面临这样一个问题:我们想为这个Calendar使用一个自定义的converter。其实这很简单,使用一个自定义converter的annotation来标记该属性:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
     private int messageType; 
     @XStreamImplicit(itemFieldName="part") 
     private List<String> content; 
     @XStreamConverter(SingleValueCalendarConverter.class) 
     private Calendar created = new GregorianCalendar(); 
     public RendezvousMessage(int messageType, String... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    }

    下面来创建这个conventer:

    public class SingleValueCalendarConverter implements Converter { 
        public void marshal(Object source, HierarchicalStreamWriter writer, 
                MarshallingContext context) { 
            Calendar calendar = (Calendar) source; 
            writer.setValue(String.valueOf(calendar.getTime().getTime())); 
        } 
         public Object unmarshal(HierarchicalStreamReader reader, 
                UnmarshallingContext context) { 
            GregorianCalendar calendar = new GregorianCalendar(); 
            calendar.setTime(new Date(Long.parseLong(reader.getValue()))); 
            return calendar; 
        } 
         public boolean canConvert(Class type) { 
            return type.equals(GregorianCalendar.class); 
        } 
    }

    接着就可以得到下面这个输出了:

    <message> 
      <type>15</type> 
      <part>firstPart</part> 
      <part>secondPart</part> 
      <created>1154097812245</created> 
    </message>

    注意,@XStreamConverter标签是自动读取的,不需要调用任何Annotations上的静态方法。XStream能简单的检查运行环境是否支持Java1.5。
    如果需要type属性作为message标签的一个属性的话:

    <message type="15"> 
      <part>firstPart</part> 
      <part>secondPart</part> 
      <created>1154097812245</created> 
    </message>

    你只需要添加一个XStreamAsAttribute annotation即可:

    @XStreamAlias("message") 
    class RendezvousMessage { 
     @XStreamAlias("type") 
        @XStreamAsAttribute 
     private int messageType; 
     @XStreamImplicit(itemFieldName="part") 
     private List<String> content; 
     @XStreamConverter(SingleValueCalendarConverter.class) 
     private Calendar created = new GregorianCalendar(); 
     public RendezvousMessage(int messageType, String... content) { 
      this.messageType = messageType; 
      this.content = Arrays.asList(content); 
     } 
    }

     

  • 评论 】 【收藏】 【 推荐给朋友 】 【字体: 】 【关闭
评论:共0条

发表评论:
评论: 
    
Copyright (C) 2005 EasyJF.com 简易java框架网 渝ICP备06004507号
如有意见请与我们联系