精华内容
下载资源
问答
  • XStream

    2019-09-19 02:50:29
    http://xstream.codehaus.org/download.html 取别名: package bean; import java.util.Date; import com.thoughtworks.xstream.annotations.XStreamAl...
    http://xstream.codehaus.org/download.html


    取别名:
    package bean;
    import java.util.Date;
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    @XStreamAlias("Query")
    public class Query {
    	private Query(){}
    	private static Query query = new Query();
    	
    	@XStreamAlias("CmdType")
    	private String CmdType;
    	
    	@XStreamAlias("SN")
    	private int sn;
    	
    	@XStreamAlias("DeviceID")
    	private String DeviceID;
    	
    	@XStreamAlias("StartTime")
    	private Date StartTime;
    	
    	@XStreamAlias("EndTime")
    	private Date EndTime;
    	
    	@XStreamAlias("FilePath")
    	private String filePath;
    	
    	@XStreamAlias("Address")
    	private String address;
    	
    	@XStreamAlias("Secrecy")
    	private int secrecy;
    	@XStreamAlias("Type")
    	private String type;
    	
    	@XStreamAlias("RecorderID")
    	private String recorderID;
    	
    	public static Query getInstance(){
    		query.setCmdType("RecordInfo");
    		query.setSn(17430);
    		query.setStartTime(new Date());
    		query.setEndTime(new Date());
    		query.setFilePath("64010000002100000001");
    		query.setAddress("Address");
    		query.setSecrecy(0);
    		query.setType("time");
    		query.setRecorderID("64010000003000000001");
    		return query;
    	}
    	
    	public String getCmdType() {
    		return CmdType;
    	}
    
    	public void setCmdType(String cmdType) {
    		CmdType = cmdType;
    	}
    
    	public int getSn() {
    		return sn;
    	}
    
    	public void setSn(int sn) {
    		this.sn = sn;
    	}
    
    	public String getDeviceID() {
    		return DeviceID;
    	}
    
    	public void setDeviceID(String deviceID) {
    		DeviceID = deviceID;
    	}
    
    	public Date getStartTime() {
    		return StartTime;
    	}
    
    	public void setStartTime(Date startTime) {
    		StartTime = startTime;
    	}
    
    	public Date getEndTime() {
    		return EndTime;
    	}
    
    	public void setEndTime(Date endTime) {
    		EndTime = endTime;
    	}
    
    	public String getFilePath() {
    		return filePath;
    	}
    
    	public void setFilePath(String filePath) {
    		this.filePath = filePath;
    	}
    
    	public String getAddress() {
    		return address;
    	}
    
    	public void setAddress(String address) {
    		this.address = address;
    	}
    
    	public String getType() {
    		return type;
    	}
    
    	public void setType(String type) {
    		this.type = type;
    	}
    
    	public String getRecorderID() {
    		return recorderID;
    	}
    
    	public void setRecorderID(String recorderID) {
    		this.recorderID = recorderID;
    	}
    
    	public int getSecrecy() {
    		return secrecy;
    	}
    	public void setSecrecy(int secrecy) {
    		this.secrecy = secrecy;
    	}
    }


    import com.thoughtworks.xstream.XStream;
    
    import bean.Query;
    
    
    public class VieoFile {
    	
    	
    	private static String xml = "<Query> <CmdType>RecordInfo</CmdType><SN>17430</SN><StartTime>2012-09-12 16:30:26.608 CST</StartTime><EndTime>2012-09-12 16:30:26.608 CST</EndTime><FilePath>64010000002100000001</FilePath><Address>Address</Address> <Secrecy>0</Secrecy><Type>time</Type> <RecorderID>64010000003000000001</RecorderID></Query>";
    	
    	public static void main(String[] args) {
    		
    		
    	/*	Query q = Query.getInstance();
    		XStream stream = new XStream();
    		stream.autodetectAnnotations(true);
    		System.out.println(stream.toXML(q));
    		*/
    		XStream stream = new XStream();
                    //指定使用别名
    		stream.autodetectAnnotations(true);
    	        //Query与Query类上的别名一致
                    stream.alias("Query", Query.class);
    		Query query = (Query)stream.fromXML(xml);
    	
    		
    		System.out.println(query.getCmdType());
    	}
    	
    
    }

    转载于:https://my.oschina.net/iyoye/blog/804110

    展开全文
  • xStream

    2019-10-10 09:45:29
    使用XStream序列化、反序列化XML数据时遇到的各种问题 现在参与的项目是一个纯Application Server,整个Server都是自己搭建的,使用JMS消息实现客户端和服务器的交互,交互的数据格式采用XML。说来惭愧,开始为了...

    现在参与的项目是一个纯Application Server,整个Server都是自己搭建的,使用JMS消息实现客户端和服务器的交互,交互的数据格式采用XML。说来惭愧,开始为了赶进度,所有XML消息都是使用字符串拼接的,而XML的解析则是使用DOM方式查找的。我很早就看这些代码不爽了,可惜一直没有时间去重构,最近项目加了几个人,而且美国那边也开始渐渐的把这个项目开发的控制权交给我们了,所以我开始有一些按自己的方式开发的机会了。因而最近动手开始重构这些字符串拼接的代码。

    XMLJava Bean的解析框架,熟悉一点的只有DigesterXStreamDigester貌似只能从XML文件解析成Java Bean对象,所以只能选择XStream来做了,而且同组的其他项目也有在用XStream。一直听说XStream的使用比较简单,而且我对ThoughtWorks这家公司一直比较有好感,所以还以为引入XStream不会花太多时间,然而使用以后才发现XStream并没有想象的你那么简单。不过这个也有可能是因为我不想改变原来的XML数据格式,而之前的XML数据格式的设计自然不会考虑到如何便利的使用XStream。因而记录在使用过程中遇到的问题,供后来人参考,也为自己以后如果打算开其源码提供参考。废话就到这里了,接下来步入正题。

    首先对于简单的引用,XStream使用起来确实比较简单,比如自定义标签的属性、使用属性和使用子标签的定义等:

    @XStreamAlias("request")
    public class XmlRequest1 {
        
    private static XStream xstream;
        
    static {
            xstream 
    = new XStream();
            xstream.autodetectAnnotations(
    true);
        }
       
        @XStreamAsAttribute
        
    private String from;
       
        @XStreamAsAttribute
        @XStreamAlias(
    "calculate-method")
        
    private String calculateMethod;
       
        @XStreamAlias(
    "request-time")
        private Date requestTime;
     
        @XStreamAlias(
    "input-files")
        
    private List<InputFileInfo> inputFiles;
       
        
    public static String toXml(XmlRequest1 request) {
            StringWriter writer 
    = new StringWriter();
            writer.append(Constants.XML_HEADER);
            xstream.toXML(request, writer);
            
    return writer.toString();
        }
        
    public static XmlRequest1 toInstance(String xmlContent) {
            
    return (XmlRequest1)xstream.fromXML(xmlContent);
    }

        @XStreamAlias(
    "input-file")
        
    public static class InputFileInfo {
            
    private String type;
            
    private String fileName;
            
        }
        
    public static void main(String[] args) {
            XmlRequest1 request 
    = buildXmlRequest();
            System.out.println(XmlRequest1.toXml(request));
        }
        
    private static XmlRequest1 buildXmlRequest() {
            
        }
    }

     对以上Request定义,我们可以得到如下结果:

    <?xml version="1.0" encoding="UTF-8"?>
    <request from="levin@host" calculate-method="advanced">
     
    <request-time>2012-11-28 17:11:54.664 UTC</request-time>
     
    <input-files>
        
    <input-file>
          
    <type>DATA</type>
          
    <fileName>data.2012.11.29.dat</fileName>
        
    </input-file>
        
    <input-file>
          
    <type>CALENDAR</type>
          
    <fileName>calendar.2012.11.29.dat</fileName>
        
    </input-file>
     
    </input-files>
    </request>

    可惜这个世界不会那么清净,这个格式有些时候貌似并不符合要求,比如request-time的格式、input-files的格式,我们实际需要的格式是这样的:

    <?xml version="1.0" encoding="UTF-8"?>
    <request from="levin@host" calculate-method="advanced">
     
    <request-time>20121128T17:51:05</request-time>
     
    <input-file type="DATA">data.2012.11.29.dat</input-file>
     
    <input-file type="CALENDAR">calendar.2012.11.29.dat</input-file>
    </request>

    对不同Date格式的支持可以是用Converter实现,在XStream中默认使用自己实现的DateConverter,它支持的格式是:yyyy-MM-dd HH:mm:ss.S 'UTC',然而我们现在需要的格式是yyyy-MM-dd’T’HH:mm:ss,如果使用XStream直接注册DateConverter,可以使用配置自己的DateConverter,但是由于DateConverter的构造函数的定义以及@XStreamConverter的构造函数参数的支持方式的限制,貌似DateConverter不能很好的支持注解方式的注册,因而我时间了一个自己的DateConverter以支持注解:

    public class LevinDateConverter extends DateConverter {
        
    public LevinDateConverter(String dateFormat) {
            
    super(dateFormat, new String[] { dateFormat });
        }
    }

    requestTime字段中需要加入以下注解定义:

    @XStreamConverter(value=LevinDateConverter.class, strings={"yyyyMMdd'T'HH:mm:ss"})
    @XStreamAlias(
    "request-time")
    private Date requestTime;

    对集合类,XStream提供了@XStreamImplicit注解,以将集合中的内容摊平到上一层XML元素中,其中itemFieldName的值为其使用的标签名,此时InputFileInfo类中不需要@XStreamAlias标签的定义:

    @XStreamImplicit(itemFieldName="input-file")
    private List<InputFileInfo> inputFiles;

    InputFileInfo中的字段,type作为属性很容易,只要为它加上@XStreamAsAttribute注解即可,而将fileName作为input-file标签的一个内容字符串,则需要使用ToAttributedValueConverter,其中Converter的参数为需要作为字符串内容的字段名:

    @XStreamConverter(value=ToAttributedValueConverter.class, strings={"fileName"})
    public static class InputFileInfo {
        @XStreamAsAttribute
        
    private String type;
    private String fileName;

    }

    XStream对枚举类型的支持貌似不怎么好,默认注册的EnumSingleValueConverter只是使用了Enum提供的name()和静态的valueOf()方法将enum转换成String或将String转换回enum。然而有些时候XML的字符串和类定义的enum值并不完全匹配,最常见的就是大小写的不匹配,此时需要写自己的Converter。在这种情况下,我一般会在enum中定义一个name属性,这样就可以自定义enum的字符串表示。比如有TimePeriodenum

    public enum TimePeriod {
        MONTHLY(
    "monthly"), WEEKLY("weekly"), DAILY("daily");
       
        
    private String name;
       
        
    public String getName() {
            
    return name;
        }
       
        
    private TimePeriod(String name) {
            
    this.name = name;
        }
       
        
    public static TimePeriod toEnum(String timePeriod) {
            
    try {
                
    return Enum.valueOf(TimePeriod.class, timePeriod);
            } 
    catch(Exception ex) {
                
    for(TimePeriod period : TimePeriod.values()) {
                    
    if(period.getName().equalsIgnoreCase(timePeriod)) {
                        
    return period;
                    }
                }
                
    throw new IllegalArgumentException("Cannot convert <" + timePeriod + "> to TimePeriod enum");
            }
        }
    }

    我们可以编写以下Converter以实现对枚举类型的更宽的容错性:

    public class LevinEnumSingleNameConverter extends EnumSingleValueConverter {
        
    private static final String CUSTOM_ENUM_NAME_METHOD = "getName";
        
    private static final String CUSTOM_ENUM_VALUE_OF_METHOD = "toEnum";
       
        
    private Class<? extends Enum<?>> enumType;
     
        
    public LevinEnumSingleNameConverter(Class<? extends Enum<?>> type) {
            
    super(type);
            
    this.enumType = type;
        }
     
        @Override
        
    public String toString(Object obj) {
            Method method 
    = getCustomEnumNameMethod();
            
    if(method == null) {
                
    return super.toString(obj);
            } 
    else {
                
    try {
                    
    return (String)method.invoke(obj, (Object[])null);
                } 
    catch(Exception ex) {
                    
    return super.toString(obj);
                }
            }
        }
     
        @Override
        
    public Object fromString(String str) {
            Method method 
    = getCustomEnumStaticValueOfMethod();
            
    if(method == null) {
                
    return enhancedFromString(str);
            }
            
    try {
                
    return method.invoke(null, str);
            } 
    catch(Exception ex) {
                
    return enhancedFromString(str);
            }
        }
       
        
    private Method getCustomEnumNameMethod() {
            
    try {
                
    return enumType.getMethod(CUSTOM_ENUM_NAME_METHOD, (Class<?>[])null);
            } 
    catch(Exception ex) {
                
    return null;
            }
        }
       
        
    private Method getCustomEnumStaticValueOfMethod() {
            
    try {
                Method method 
    = enumType.getMethod(CUSTOM_ENUM_VALUE_OF_METHOD, (Class<?>[])null);
                
    if(method.getModifiers() == Modifier.STATIC) {
                    
    return method;
                }
                
    return null;
            } 
    catch(Exception ex) {
                
    return null;
            }
        }
       
        
    private Object enhancedFromString(String str) {
            
    try {
                
    return super.fromString(str);
            } 
    catch(Exception ex) {
                
    for(Enum<?> item : enumType.getEnumConstants()) {
                    
    if(item.name().equalsIgnoreCase(str)) {
                        
    return item;
                    }
                }
                
    throw new IllegalStateException("Cannot converter <" + str + "> to enum <" + enumType + ">");
            }
        }
    }

    如下方式使用即可:

    @XStreamAsAttribute
    @XStreamAlias(
    "time-period")
    @XStreamConverter(value
    =LevinEnumSingleNameConverter.class)
    private TimePeriod timePeriod;

    double类型,貌似默认的DoubleConverter实现依然不给力,它不支持自定义的格式,比如我们想在序列化的时候用一下格式: ###,##0.0########,此时又需要编写自己的Converter

    public class FormatableDoubleConverter extends DoubleConverter {
        
    private String pattern;
        
    private DecimalFormat formatter;
       
        
    public FormatableDoubleConverter(String pattern) {
            
    this.pattern = pattern;
            
    this.formatter = new DecimalFormat(pattern);
        }
       
        @Override
        
    public String toString(Object obj) {
            
    if(formatter == null) {
                
    return super.toString(obj);
            } 
    else {
                
    return formatter.format(obj);
            }
        }
       
        @Override
        
    public Object fromString(String str) {
            
    try {
                
    return super.fromString(str);
            } 
    catch(Exception ex) {
                
    if(formatter != null) {
                    
    try {
                        
    return formatter.parse(str);
                    } 
    catch(Exception e) {
                        
    throw new IllegalArgumentException("Cannot parse <" + str + "> to double value", e);
                    }
                }
                
    throw new IllegalArgumentException("Cannot parse <" + str + "> to double value", ex);
            }
        }
       
        
    public String getPattern() {
            
    return pattern;
        }
    }

    使用方式和之前的Converter类似:

    @XStreamAsAttribute
    @XStreamConverter(value
    =FormatableDoubleConverter.class, strings={"###,##0.0########"})
    private double value;

    最后,还有两个XStream没法实现的,或者说我没有找到一个更好的实现方式的场景。第一种场景是XStream不能很好的处理对象组合问题:

    在面向对象编程中,一般尽量的倾向于抽取相同的数据成一个类,而通过组合的方式构建整个数据结构。比如Student类中有nameaddressAddress是一个类,它包含citycodestreet等信息,此时如果要对Student对象做如下格式序列化:

    <student name=”Levin”>
     
    <city>shanghai</city>
     
    <street>zhangjiang</street>
     
    <code>201203</code>
    </student>

    貌似我没有找到可以实现的方式,XStream能做是在中间加一层address标签。对这种场景的解决方案,一种是将Address中的属性平摊到Student类中,另一种是让Student继承自Address类。不过貌似这两种都不是比较理想的办法。

    第二种场景是XStream不能很好的处理多态问题:

    比如我们有一个Trade类,它可能表示不同的产品:

    public class Trade {
        
    private String tradeId;
        private Product product;

    }
    abstract class Product {
        
    private String name;
        
    public Product(String name) {
            
    this.name = name;
    }

    }
    class FX extends Product {
        
    private double ratio;
        
    public FX() {
            
    super("fx");
        }
        
    }
    class Future extends Product {
        
    private double maturity;
        
    public Future() {
            
    super("future");
        }
        
    }

    通过一些简单的设置,我们能得到如下XML格式:

    <trades>
     
    <trade trade-id="001">
        
    <product class="levin.xstream.blog.FX" name="fx" ratio="0.59"/>
     
    </trade>
     
    <trade trade-id="002">
        
    <product class="levin.xstream.blog.Future" name="future" maturity="2.123"/>
     
    </trade>
    </trades>

    作为数据文件,对Java类的定义显然是不合理的,因而简单一些,我们可以编写自己的Converterclass属性从product中去除:

    xstream.registerConverter(new ProductConverter(
            xstream.getMapper(), xstream.getReflectionProvider()));
     
        
    public ProductConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
            
    super(mapper, reflectionProvider);
        }
       
        @Override
        
    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
            
    return Product.class.isAssignableFrom(type);
        }
     
        @Override
        
    protected Object instantiateNewInstance(HierarchicalStreamReader reader, UnmarshallingContext context) {
            Object currentObject 
    = context.currentObject();
            
    if(currentObject != null) {
                
    return currentObject;
            }
           
            String name 
    = reader.getAttribute("name");
            
    if("fx".equals(name)) {
                
    return reflectionProvider.newInstance(FX.class);
            } 
    else if("future".equals(name)) {
                
    return reflectionProvider.newInstance(Future.class);
            }
            
    throw new IllegalStateException("Cannot convert <" + name + "> product");
        }
    }

    在所有Production上定义@XStreamAlias(“product”)注解。这时的XML输出结果为:

    <trades>
     
    <trade trade-id="001">
        
    <product name="fx" ratio="0.59"/>
     
    </trade>
     
    <trade trade-id="002">
        
    <product name="future" maturity="2.123"/>
     
    </trade>
    </trades>

    然而如果有人希望XML的输出结果如下呢?

    <trades>
     
    <trade trade-id="001">
        
    <fx ratio="0.59"/>
     
    </trade>
     
    <trade trade-id="002">
        
    <future maturity="2.123"/>
     
    </trade>
    </trades>

    大概找了一下,可能可以定义自己的Mapper来解决,不过XStream的源码貌似比较复杂,没有时间深究这个问题,留着以后慢慢解决吧。

    补充:

    Map类型数据,XStream默认使用以下格式显示:

    <map class="linked-hash-map">
        
    <entry>
          
    <string>key1</string>
          
    <string>value1</string>
        
    </entry>
        
    <entry>
          
    <string>key2</string>
          
    <string>value2</string>
        
    </entry>
     
    </map>

     

    但是对一些简单的Map,我们希望如下显示:

     <map>
        
    <entry key="key1" value="value1"/>
        
    <entry key="key2" value="value2"/>
     
    </map>

    对这种需求需要通过编写Converter解决,继承自MapConverter,覆盖以下函数,这里的Map默认keyvalue都是String类型,如果他们不是String类型,需要另外添加逻辑:

    @SuppressWarnings("rawtypes")
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer,
            MarshallingContext context) {
        Map map 
    = (Map) source;
        
    for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
            Entry entry 
    = (Entry) iterator.next();
            ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper()
                    .serializedClass(Map.Entry.
    class), entry.getClass());
     
            writer.addAttribute(
    "key", entry.getKey().toString());
            writer.addAttribute(
    "value", entry.getValue().toString());
            writer.endNode();
        }
    }
     
    @Override
    @SuppressWarnings({ 
    "unchecked""rawtypes" })
    protected void putCurrentEntryIntoMap(HierarchicalStreamReader reader,
            UnmarshallingContext context, Map map, Map target) {
        Object key 
    = reader.getAttribute("key");
        Object value 
    = reader.getAttribute("value");
     
        target.put(key, value);
    }

    但是只是使用Converter,得到的结果多了一个class属性:

     <map class="linked-hash-map">
        
    <entry key="key1" value="value1"/>
        
    <entry key="key2" value="value2"/>
     
    </map>

    XStream中,如果定义的字段是一个父类或接口,在序列化是会默认加入class属性以确定反序列化时用的类,为了去掉这个class属性,可以定义默认的实现类来解决(虽然感觉这种解决方案不太好,但是目前还没有找到更好的解决方案)。

    xstream.addDefaultImplementation(LinkedHashMap.class, Map.class);

     

    展开全文
  • xstream

    2017-12-09 16:22:00
    xstream 转载于:https://www.cnblogs.com/lishupeng/p/8011817.html

    xstream

    转载于:https://www.cnblogs.com/lishupeng/p/8011817.html

    展开全文
  • Xstream

    2019-08-02 11:35:33
    NULL 博文链接:https://81365341.iteye.com/blog/1969912
  • XStream

    2013-03-27 12:57:07
    XStream是一个将对象序列化为xml并解析xml为对象的框架,主页位于http://xstream.codehaus.org。使用非常简单   引入依赖: &lt;dependency&...com.thoughtworks.xstream&...xstream&lt;/...

    XStream是一个将对象序列化为xml并解析xml为对象的框架,主页位于http://xstream.codehaus.org。使用非常简单

     

    引入依赖:

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.2</version>
    </dependency>

    需要的依赖

    XmlPull一个xmlpull parser api用来判断具体的xml解析实现(DOM、StAX等)工厂

    其他可供选择的Xpp3DOM4J

     

    1、创建待序列化的对象:

    Person.java

    public class Person {
    
        private Integer id;
        private String  username;
        private String  password;
        private Address address;
        ...
    }

     Person中包含一个Address作为Field

    public class Address {
    
        private String street;
        private String city;
        ......
    }

     

    2、序列化和反序列化

    使用XStream只需要实例化一个XStream对象即可:

    XStream xstream = new XStream();
    //采用这个构造器默认需要依赖:xstream-[version].jar, xpp3-[version].jar and xmlpull-[version].jar
     或者采用DOM的方式解析:
    XStream xstream = new XStream(new DomDriver()); 
    //此时不需要XPP3

    或者基于事件的StAX

    XStream xstream = new XStream(new StaxDriver()); 
    //如果采用Java 6,也不需要xpp3.将采用默认的JAXB
    //对象序列化为xml
    xstream.toXML(Object)
    
    //xml反序列化为对象
    xstream.fromXML(xml)
    

     一个例子:

    Person p = new Person();
    p.setId(1);
    p.setUsername("robin");
    p.setPassword("123");
    p.setAddress(new Address("xxRoad", "chengdu"));
    xstream.toXML(p);
    

     输出为:

    <org.java.codelib.xstream.Person>
      <id>1</id>
      <username>robin</username>
      <password>123</password>
      <address>
        <street>xxRoad</street>
        <city>chengdu</city>
      </address>
    </org.java.codelib.xstream.Person>

     

    3、alias

    这里可以看到生成的xml中root element名字为class,如果需要修改就需要用到

    xstream.alias("person", Person.class);

    这样就会用person替代org.java.codelib.xstream.Person

    同样对于field也可以使用alias:

    xstream.aliasField("personId", Person.class, "id");

    这样就会将Person中的id替换为<personId>1</personId>

    其他的还有aliasAttribute即将field作为attribute时并采用别名,当前前提是需要设置field作为attribute:

    XStream xstream = new XStream(new StaxDriver());
    xstream.alias("person", Person.class);
    xstream.useAttributeFor(Person.class, "id");
    xstream.aliasAttribute("personId", "id");
    xstream.toXML(p);

    输出为:

    <?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><address><street>xxRoad</street><city>chengdu</city></address></person> 

    说到设置field作为attribute如果field是一个自定义对象,或者需要将Date之类的属性格式化输出,如本例中的Address该如何处理?这就是另外一个话题

    需要说明的是以上在序列化为xml的时候使用了alias,那么在反序列化的时候同样需要这些相应的代码,不然可能会抛出UnknownFieldException

     

    4、convertors

    convertor的作用是在做序列化或反序列化的时候,将对象中的属性按照特定的形式输出或转化,在XStream 中默认初始化了大量的必要convertors,见http://xstream.codehaus.org/converters.html 或者在XStream.java中有方法setupConverters()。

    自定义一个convertor需要两步:

    1、实现Converter接口及相关方法:

    public class DateConverter implements Converter {
    
        @Override
        public boolean canConvert(Class type) {
            return type.equals(Date.class);
        }
    
        @Override
        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            writer.setValue(dateFormat.format((Date) source));
        }
    
        @Override
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                return dateFormat.parse(reader.getValue());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }

     

    2、在xstream中注册该convertor:

    xstream.registerConverter(new DateConverter());

     输出

    <?xml version="1.0" ?><person><id>1</id><username>robin</username><password>123</password><birthday>2013-02-17 15:12:53</birthday><address><street>xxRoad</street><city>chengdu</city></address></person>

    当然,xstream针对Date也做了默认的实现,只不过默认输出为UTC格式

    现在我们回到上面的问题,即将对象Address作为Person的属性,下面是一个convertor的实现:

    public class PersonConverter implements Converter {
    
        @SuppressWarnings("rawtypes")
        @Override
        public boolean canConvert(Class type) {
            return type.equals(Person.class);
        }
    
        @Override
        public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
            Person person = (Person) source;
            if (person != null) {
                Address address = person.getAddress();
                if (address != null) {
                    if (StringUtils.isNotBlank(address.getStreet())) {
                        writer.addAttribute("street", address.getStreet());
                    }
                    if (StringUtils.isNotBlank(address.getCity())) {
                        writer.addAttribute("city", address.getCity());
                    }
                }
    
                //address
                if (person.getBirthday() != null) {
                    writer.startNode("birthday");
                    context.convertAnother(person.getBirthday(), new DateConverter());
                    writer.endNode();
                }
    
                //username
                if (person.getUsername() != null) {
                    writer.startNode("username");
                    context.convertAnother(person.getUsername());
                    writer.endNode();
                }
                //other fields
            }
        }
    
        @Override
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
            Person p = new Person();
            Address address = new Address();
            address.setCity(reader.getAttribute("city"));
            address.setStreet(reader.getAttribute("street"));
            p.setAddress(address);
    
            while (reader.hasMoreChildren()) {
                reader.moveDown();
                if ("birthday".equals(reader.getNodeName())) {
                    Date date = (Date) context.convertAnother(p, Date.class, new DateConverter());
                    p.setBirthday(date);
                } else if ("username".equals(reader.getNodeName())) {
                    p.setUsername((String) context.convertAnother(p, String.class));
                }
                //other fields
                reader.moveUp();
            }
    
            return p;
        }
    }

    其中序列化时输出:

     <?xml version="1.0" ?><person street="xxRoad" city="chengdu"><birthday>2013-02-17 16:34:24</birthday><username>robin</username></person>

    当然如果作为fields的对象只有一个属性就简单得多了,在http://xstream.codehaus.org/alias-tutorial.html#attributes有例子可供参考

     

    5、implicitCollections
    考虑Person有列表属性:

    private List<Address> addresses;

     在序列化为xml时:

    <?xml version="1.0" ?><person><addresses><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></addresses></person>

     当然有时候并不想要addresses,这就是XStream中的implicitCollections:对集合的属性在序列化是不想显示roottag。值需要很简单的处理:

            XStream xstream = new XStream(new StaxDriver());
            xstream.alias("person", Person.class);
            xstream.alias("address", Address.class);
            xstream.addImplicitCollection(Person.class, "addresses");
            return xstream.toXML(formatPerson());

     输出为: 

    <?xml version="1.0" ?><person><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></person>

     

    6、annotation
    以上说的内容都支持annotation:

    @XStreamAlias("person")
    public class Person {
    
        @XStreamAlias("personId")
        @XStreamAsAttribute
        private Integer       id;
        private String        username;
        private String        password;
        @XStreamConverter(DateConverter.class)
        private Date          birthday;
        private Address       address;
        @XStreamImplicit(itemFieldName = "address")
        private List<Address> addresses;
    }
    @XStreamAlias("person")
    public class Address {
    
        @XStreamAsAttribute
        private String street;
        @XStreamAsAttribute
        private String city;
    }

    需要加上autodetectAnnotations(true)

    XStream xstream = new XStream(new StaxDriver());
    xstream.autodetectAnnotations(true);
    return xstream.toXML(p);

    输出:

    <?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><birthday>2013-02-17 17:08:00</birthday><address street="road_1" city="chengdu"></address><address street="road_2" city="chengdu"></address></person>

    7、其他

    xstream提供了对json的解析以及持久化(文件系统)的支持,这里就不再介绍了

     

     

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,966
精华内容 1,986
关键字:

xstream