`

使用XStream是实现XML与Java对象的转换(3)--注解

阅读更多

六、使用注解(Annotation)

总是使用XStream对象的别名方法和注册转换器,会让人感到非常的乏味,又会产生很多重复性代码,于是我们可以使用注解的方式来配置要序列化的POJO对象。

1,最基本的注解:类的别名性注解和字段的别名性注解(XStreamAlias)

 

有这样一段代码:

import com.thoughtworks.xstream.XStream;
 
public class XStreamTest3 {
   public static void main(String[] args) {
      XStream stream = new XStream();
      RendezvousMessage msg = new RendezvousMessage(15);
      System.out.println(stream.toXML(msg));
   }
 
}
class RendezvousMessage {
  
   private int messageType;
  
   public RendezvousMessage(int messageType) {
      this.messageType = messageType;
   }
}

 

运行结果是:

<cn.tjpu.zhw.xml.RendezvousMessage>
  <messageType>15</messageType>
</cn.tjpu.zhw.xml.RendezvousMessage>

 

 

如果我们需要将输出的XML文本是这样:

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

 

该怎么办?

我们当然可以在main方法中调用XStream对象的别名映射方法进行处理,但我们也可以使用更简单的注解的方式进行处理。

RendezvousMessage类的定义进行注解如下:

//对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
  
   //对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
  
   public RendezvousMessage(int messageType) {
      this.messageType = messageType;
   }
}

 

但是,我们进行注解之后发现输出的结果并没有改变,为什么?

因为XStream对象默认是不读取和识别注解的,需要我们主动提醒它,而后XStream对象才能在转换的的时候读取注解。

更改main方法如下:

public static void main(String[] args) {
      XStream stream = new XStream();
      //通知XStream对象读取并识别RendezvousMessage中的注解
      stream.processAnnotations(RendezvousMessage.class);
      RendezvousMessage msg = new RendezvousMessage(15);
      System.out.println(stream.toXML(msg));
}

 

这样输出的结果就能与预想的一样了。

注意:当使用XStream对象处理一个被注解的类型时,XStream对象也会处理所有与其相关的类型的注解信息,即该类型的父类、父接口、所有子类的注解。

processAnnotations方法还有一个重载的方法,是以Class []作为参数的。

2,隐式集合注解(XStreamImplicit)

现在我们给RendezvousMessage类添加一个List集合字段,并且更改一下RendezvousMessage的构造方法,新的代码如下:

import java.util.Arrays;
import java.util.List;
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
 
public class XStreamTest3 {
   public static void main(String[] args) {
      XStream stream = new XStream();
      //通知XStream对象读取并识别RendezvousMessage中的注解
      stream.processAnnotations(RendezvousMessage.class);
      RendezvousMessage msg = new RendezvousMessage(15,"first","second");
      System.out.println(stream.toXML(msg));
   }
 
}
 
//对类的别名性注解
@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);
   }
}

 

运输出结果如下:

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

 

但是,如果我们想让输出的XML格式如下:

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

 

该怎么办?

现在我们给集合字段添加隐式集合性注解,以去除集合的根节点:

//对类的别名性注解
@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>
  <string>first</string>
  <string>second</string>
</message>

 

输出的结果中,集合的每一个子节点的节点名都是string,现在需要将子节点的节点名改为part,这样就需要继续更改注解项:

//对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
  
   //对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
  
   //对隐式集合的注解,将每一个子节点的节点名都改为part
   @XStreamImplicit(itemFieldName="part")
   private List<String> content;
  
   public RendezvousMessage(int messageType, String ... content) {
      this.messageType = messageType;
      this.content = Arrays.asList(content);
   }
}

 

这样输出的结果就能够跟预想的一样了,成功了!!!

注意:隐式集合注解同样可以用于数组和Map对象。

3,注解转换器(XStreamConverter)

现在我们再给RendezvousMessage类添加两个字段,一个boolean字段和一个时间Calendar字段,代码如下:

public class XStreamTest3 {
   public static void main(String[] args) {
      XStream stream = new XStream();
      // 通知XStream对象读取并识别RendezvousMessage中的注解
      stream.processAnnotations(RendezvousMessage.class);
      RendezvousMessage msg = new RendezvousMessage(15,false,"first","second");
      System.out.println(stream.toXML(msg));
   }
 
}
 
// 对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
 
   // 对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
 
   // 隐式集合性注解
   @XStreamImplicit(itemFieldName = "part")
   private List<String> content;
 
   private boolean important;
 
   private Calendar created = new GregorianCalendar();
 
   // 再次对构造方法进行了改造
   public RendezvousMessage(int messageType, boolean important,
        String... content) {
      this.messageType = messageType;
      this.important = important;
      this.content = Arrays.asList(content);
   }
 
}

 

运行结果如下:

<message>
  <type>15</type>
  <part>first</part>
  <part>second</part>
  <important>false</important>
  <created>
    <time>1387534087343</time>
    <timezone>Asia/Shanghai</timezone>
  </created>
</message>

 

现在,我们要将输出结果改造为:

<message>
  <type>15</type>
  <part>firstPart</part>
  <part>secondPart</part>
  <important>no</important>
  <created>1379430873703</created>
</message>

 

该如何做?

首先,我们使用注解处理Calendar时间字段的转换,先定义一个时间的转换器SingleValueCalendarConverter,代码如下:

package cn.tjpu.zhw.xml;
 
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
 
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 
//必须是public类型
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);
    }
}

 

 

然后,我们需要使用SingleValueCalendarConverter转换器对Calendar字段进行注解:

//对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
  
   //对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
  
   //对隐式集合的注解,将每一个子节点的节点名都改为part
   @XStreamImplicit(itemFieldName="part")
   private List<String> content;
  
   private boolean important;
  
   //为该字段的注解指定转换器
   @XStreamConverter(SingleValueCalendarConverter.class)
   private Calendar created = new GregorianCalendar();
  
   public RendezvousMessage(int messageType, String ... content) {
      this.messageType = messageType;
      this.content = Arrays.asList(content);
   }
}

 

运行结果如下:

<message>
  <type>15</type>
  <part>first</part>
  <part>second</part>
  <important>false</important>
  <created>1387534774062</created>
</message>

 

 

但是我们发现important节点中的内容是truefalse,怎样让它变成yesno呢?

我们可以使用框架为我们提供的一个转换器BooleanConverter

修改RendezvousMessage的类定义:

//对类别名的注解
@XStreamAlias("message")
class RendezvousMessage {
  
   //对字段别名的注解
   @XStreamAlias("type")
   private int messageType;
  
   //对隐式集合的注解,将每一个子节点的节点名都改为part
   @XStreamImplicit(itemFieldName="part")
   private List<String> content;
  
   //将true/false改为yes/no
   @XStreamConverter(value=BooleanConverter.class, booleans={false}, strings={"yes", "no"})
   private boolean important;
  
   //为该字段添加转换器注解
   @XStreamConverter(SingleValueCalendarConverter.class)
   private Calendar created = new GregorianCalendar();
  
   public RendezvousMessage(int messageType, boolean important, String... content) {
      this.messageType = messageType;
      this.important = important;
      this.content = Arrays.asList(content);
   }
}

 

运行结果如下:

<message>
  <type>15</type>
  <part>first</part>
  <part>second</part>
  <important>no</important>
  <created>1387534827609</created>
</message>

 

这正是我们想要的!!!!

4,属性注解

现在我们想将上面的XML格式改造成为:

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

 

,也就是把type节点和important节点作为父节点的属性,该怎么做?

答案是,使用属性注解:

@XStreamAsAttribute

 

代码如下:

public class XStreamTest3 {
   public static void main(String[] args) {
      XStream stream = new XStream();
      // 通知XStream对象读取并识别RendezvousMessage中的注解
      stream.processAnnotations(RendezvousMessage.class);
      RendezvousMessage msg = new RendezvousMessage(15, false, "first",
           "second");
      System.out.println(stream.toXML(msg));
   }
 
}
 
// 对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
 
   //将type节点变成属性
   @XStreamAsAttribute
   // 对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
 
   // 隐式集合性注解
   @XStreamImplicit(itemFieldName = "part")
   private List<String> content;
 
  
   //将important节点变成属性
   @XStreamAsAttribute
   // 将true/false改为yes/no
   @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
        "yes", "no" })
   private boolean important;
 
   @XStreamConverter(SingleValueCalendarConverter.class)
   private Calendar created = new GregorianCalendar();
 
   public RendezvousMessage(int messageType, boolean important,
        String... content) {
      this.messageType = messageType;
      this.important = important;
      this.content = Arrays.asList(content);
   }
}
 

 

结果是:

<message type="15" important="no">
  <part>first</part>
  <part>second</part>
  <created>1387540760390</created>
</message>

 

我们有成功了!!!!

 

5,使用注解将字段转换为父节点文本内容

我们如果想得到的XML是如下形式:

<message type="15" important="no" created="1154097812245">This is the message content.</message>

 

就是将typeimportantcreated三个节点全部变属性,并且将content节点的内容变为父节点message的内容,如何做?

这就需要用到

ToAttributedValueConverter转换器注解

代码如下:

// 新加的转换器注解
@XStreamConverter(value = ToAttributedValueConverter.class, strings = { "content" })
// 对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
 
   // 将type节点变成属性
   @XStreamAsAttribute
   // 对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
 
   // 隐式集合性注解
   @XStreamImplicit(itemFieldName = "part")
   private List<String> content;
 
   // 将important节点变成属性
   @XStreamAsAttribute
   // 将true/false改为yes/no
   @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
        "yes", "no" })
   private boolean important;
 
   @XStreamConverter(SingleValueCalendarConverter.class)
   private Calendar created = new GregorianCalendar();
 
   public RendezvousMessage(int messageType, boolean important,
        String... content) {
      this.messageType = messageType;
      this.important = important;
      this.content = Arrays.asList(content);
   }
}

 

但是运行之后,会发现,运行结果根本与我们预期的不一样,为什么?

因为ToAttributedValueConverter转换器接受的content节点必须是String类型或者有一个转换器将content装换为String类型!!!

例如,将content节点变为String类型:

//新加的转换注解
@XStreamConverter(value = ToAttributedValueConverter.class, strings = { "content" })
//对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
 
   // 对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
 
   //由原来的List<String>类型变为String类型
   private String content;
  
 
   // 将true/false改为yes/no
   @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
        "yes", "no" })
   private boolean important;
 
// @XStreamConverter(SingleValueCalendarConverter.class)
// private Calendar created = new GregorianCalendar();
 
   // 再次对构造方法进行了改造
   public RendezvousMessage(int messageType, boolean important,
        String content) {
      this.messageType = messageType;
      this.important = important;
      this.content = content;
   }
}

 

运行结果为:

<message type="15" important="no">这是一大串content节点的内容</message>

 

虽然typeimportant节点没有使用@XStreamAsAttribute注解,但是却被隐式的转换为属性。

 

6,使用注解忽略某些字段

忽略messageType字段可以使用@XStreamOmitField注解

代码如下:

//对类的别名性注解
@XStreamAlias("message")
class RendezvousMessage {
 
   //忽略messageType字段
   @XStreamOmitField
   // 将type节点变成属性
   @XStreamAsAttribute
   // 对字段的别名性注解
   @XStreamAlias("type")
   private int messageType;
 
   // 隐式集合性注解
   @XStreamImplicit(itemFieldName = "part")
   private List<String> content;
  
 
   // 将important节点变成属性
   @XStreamAsAttribute
   // 将true/false改为yes/no
   @XStreamConverter(value = BooleanConverter.class, booleans = { false }, strings = {
        "yes", "no" })
   private boolean important;
 
   @XStreamConverter(SingleValueCalendarConverter.class)
   private Calendar created = new GregorianCalendar();
 
   // 再次对构造方法进行了改造
   public RendezvousMessage(int messageType, boolean important,
        String... content) {
      this.messageType = messageType;
      this.important = important;
      this.content = Arrays.asList(content);
   }
}

 

运行结果:

<message important="no">
  <part>first</part>
  <part>second</part>
  <created>1387544212500</created>
</message>

 

 

7,自动检测注解

之前我们启用某个类的注解时,都需要使用processAnnotations方法通知xstream对象解析注解类,其实我们还有一个更简便的模式,即调用autodetectAnnotations(true)方法,让xstream对象自动检测注解类:

public class XStreamTest3 {
   public static void main(String[] args) {
      XStream stream = new XStream();
//    // 通知XStream对象读取并识别RendezvousMessage中的注解
//    stream.processAnnotations(RendezvousMessage.class);
      //自动检测注解
      stream.autodetectAnnotations(true);
      RendezvousMessage msg = new RendezvousMessage(15, false, "first","second");
      System.out.println(stream.toXML(msg));
   }
}

 

注意:1,自动检测注解模式,会使XStream的解析变慢!2,在任何地方调用processAnnotations方法之后,自动检测注解模式将会被关闭。

 

 

 

 

 

 

 

 

 

1
0
分享到:
评论
4 楼 forestqqqq 2014-01-02  
kongxuan 写道
在项目中用过xstream,后来随着接口访问量变大,xstream成为性能瓶颈。后换成了阿里的fastjson来表示结构化数据,弃用xml以及xstream,性能提升很多

XStream在序列化速度上确实赶不上许多其他框架,但是XStream使用方便,上手快。其实我学习XStream是学习XStream组织和构建框架的方法。
3 楼 kongxuan 2014-01-02  
在项目中用过xstream,后来随着接口访问量变大,xstream成为性能瓶颈。后换成了阿里的fastjson来表示结构化数据,弃用xml以及xstream,性能提升很多
2 楼 forestqqqq 2013-12-21  
Neoman 写道
我目标在自己的项目里,也是用他。xstream似乎有个缺点,硬编码到java对象里的属性值,经过xstream后,会被干掉

只要不是static修饰的属性应该都可以序列化和反序列化
1 楼 Neoman 2013-12-21  
我目标在自己的项目里,也是用他。xstream似乎有个缺点,硬编码到java对象里的属性值,经过xstream后,会被干掉

相关推荐

    使用XStream是实现XML与Java对象的转换(4)--转换器

    XStream是一个强大的库,专门用于XML与Java对象之间的互相转换。这篇博文将深入探讨如何利用XStream的转换器功能来优化这一过程。 XStream的核心原理是通过反射机制自动将Java对象映射到XML结构,并反之亦然。然而...

    xstream轻松解析xml到java对象

    以下是一个简单的示例,演示如何使用XStream进行XML与Java对象的转换: ```java import com.thoughtworks.xstream.XStream; class User { private String name; private int age; // getters and setters ...

    好用的xStream XML和JAVA对象互相转换的简单示例

    XStream是一个轻量级、高性能的库,能够将Java对象序列化为XML,同时也能将XML反序列化回Java对象,实现XML和Java对象的互相转换。 首先,我们需要引入XStream库。在给定的描述中提到了两个依赖文件:xstream-1.3.1...

    java 利用Xstream注解生成和解析xml

    总结起来,Xstream通过注解提供了一种简洁、直观的方式来处理XML和Java对象之间的转换。这种灵活性使得在Java项目中处理XML数据变得更加简单,尤其在需要频繁进行序列化和反序列化的场景下。通过熟练掌握Xstream的...

    Xstream_java对象和xml的互相转换

    XStream 的核心概念是通过自动映射 Java 类和 XML 节点来实现对象和 XML 的转换。它通过反射和自定义转换器机制来完成这一过程。默认情况下,XStream 可以处理大多数标准的 Java 类型,包括基本类型、集合、Map 等。...

    XStream在Java对象和XML之间相互转换

    XStream是一款强大的Java库,主要用于将Java对象序列...在实际开发中,XStream的简单性和灵活性使其成为处理Java对象与XML数据之间转换的首选工具。通过合理配置和使用,可以极大地提高开发效率并简化数据处理流程。

    XStream解析xml 转换成对象案例

    XStream通过映射XML节点到Java类的字段来实现对象的序列化和反序列化。这意味着你需要定义一个Java类,该类的字段对应于XML文档中的元素。XStream会自动处理这个映射过程,无需编写复杂的DOM或SAX解析代码。 下面是...

    xStream学习xml,JASON,JAVA对象转换

    XStream库则是Java世界中一个强大的工具,它能够方便地实现XML和JSON与Java对象之间的互相转换。这篇博客文章,标题为“xStream学习xml,JASON,JAVA对象转换”,显然会探讨如何利用XStream来处理这两种数据格式。 ...

    springMVC整合xStream实现对象和xml转换

    要实现"springMVC整合xStream实现对象和xml转换",我们需要以下步骤: 1. **引入依赖**:在项目的pom.xml文件中,添加XStream库的依赖。 2. **创建Controller**:创建一个SpringMVC Controller类,例如`...

    xml与java对象映射

    Java工具如JAXB和XML Beans可以直接使用XSD文件生成Java类,从而实现对象到XML的严格映射。 总之,XML与Java对象的映射是Java开发中的重要环节,涉及多种技术和工具。开发者可以根据项目需求选择合适的工具,如JAXB...

    XStream解析XML实例

    **XStream解析XML实例** ...总结,XStream是一个强大且易于使用的工具,它简化了Java与XML之间的转换。通过理解上述概念和示例,开发者可以有效地利用XStream来处理XML数据,无论是在常规Java项目还是Android应用中。

    xstream-1.3.1.jar javabean与xml之间的转化

    XStream 是一个强大的 Java 库,它允许程序员以一种简单直观的方式将 Java 对象序列化为 XML,同时也可以从 XML 文档反序列化回 ...在项目中使用 xstream-1.3.1.jar,可以轻松实现 Java 对象与 XML 文档之间的转换。

    xml和java对象互转

    XStream的核心理念是通过简单的注解或者类定义,将XML结构直接映射到Java对象的属性上,从而实现无痛的转换。 要使用XStream进行XML和Java对象的转换,首先需要将其引入项目。在给定的压缩包中包含的"jar包"很可能...

    xStream xml to bean

    xStream的核心思想是通过反射和类型映射来实现对象与XML之间的转换。它使用一种称为“annoation”的机制,允许开发者自定义XML的元素和属性名,以匹配Java对象的字段。这样,即使Java对象的结构复杂,xStream也能...

    Xstream生产xml和解析xml

    Xstream是一款强大的Java库,用于实现Java对象与XML文档之间的转换。这种转换不仅支持基本数据类型,也适用于复杂的数据结构,包括自定义类和集合。Xstream的设计旨在简化序列化过程,使得开发者能够轻松地在Java...

    XStream在JavaBean与XML/JSON 之间相互转换

    **XStream:JavaBean与XML/JSON之间的转换大师** XStream是一个开源库,它为Java对象提供了简单且直观的XML序列化和反序列化的解决方案。它不仅能够将Java对象转换成XML,反之亦然,还能支持JSON格式的转换。这个...

    使用XStream序列化/反序列化对象

    通过简单的API,它可以方便地实现对象的序列化和反序列化,同时支持复杂的数据结构和自定义转换逻辑。在`XStreamTest.java`、`Team.java`和`Person.java`这些文件中,我们可以看到如何在实际项目中应用这些概念。

    如何将java对象转换成xml

    - 使用`toXML()`方法将Java对象转换为XML字符串,或者使用`fromXML()`方法将XML字符串反序列化回Java对象。 4. **XML到Java对象的转换**: - JAXB的`Unmarshaller`类用于此操作,通过`unmarshal`方法从XML文件或...

    XStream XML解析

    **XStream XML解析** ...总之,XStream 提供了一种高效且直观的 Java 对象与 XML 之间的转换方法,尤其适用于那些需要频繁进行对象序列化的项目。理解和掌握 XStream 的使用,可以极大地提升开发效率并简化代码维护。

Global site tag (gtag.js) - Google Analytics