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

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

  • XStream Converter入门【翻译】
    作者: stef_wu  来源:easyjf  发布时间:2007-11-29 15:05:00
  • 1、简单的转换器:

    首先创建示例的环境,
    下面介绍的是最基础的转换器,首先创建一个Person类:

    package com.thoughtworks.xstream.examples; 
     public class Person { 
             private String name; 
             public String getName() { 
                    return name; 
            } 
             public void setName(String name) { 
                    this.name = name; 
            } 
     }

     接着,我们创建一个实例,并转化他:

    package com.thoughtworks.xstream.examples; 
    import com.thoughtworks.xstream.XStream; 
    import com.thoughtworks.xstream.io.xml.DomDriver; 
    public class PersonTest { 
           public static void main(String[] args) { 
                    Person person = new Person(); 
                    person.setName("Guilherme"); 
     
                    XStream xStream = new XStream(new DomDriver()); 
                    System.out.println(xStream.toXML(person)); 
            } 
    }

     如你所料,得到下面的结果:

    <com.thoughtworks.xstream.examples.Person> 
      <name>Guilherme</name> 
    </com.thoughtworks.xstream.examples.Person>

    下面我们为person类创建一个别名:

    XStream xStream = new XStream(new DomDriver()); 
    xStream.alias("person", Person.class); 
    System.out.println(xStream.toXML(person));

    现在的结果就很易读了:

    <person> 
      <name>Guilherme</name> 
    </person>

    到此,我们已经建立好一个可以供我们实验的基础例子了,下面我们来看看XStream的转换器能为我们做些什么:
    2,创建一个Person转换器:
    下面我们来创建一个简单的转换器,它能:
    1,用来转换Person类
    2,将Person实例转换成XML
    3,将xml转换为Person实例
    首先创建一个PersonConverter类,并让这个类实现Converter接口:

    package com.thoughtworks.xstream.examples; 
    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 class PersonConverter implements Converter { 
            public boolean canConvert(Class clazz) { 
                    return false; 
            } 
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
            } 
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    return null; 
            } 
    }

    下面,我们首先告诉转换器,我们只能转换Person类,而不是别的类,包括其子类:

    public boolean canConvert(Class clazz) { 
            return clazz.equals(Person.class); 
    }

    这一步很简单,除非你是用来处理泛型的转换器是会困难一点。

    Marshal方法是用来将对象转换为XML的,他有三个参数:
    1,我们准备转换的对象
    2,我们准备输出对象的writer
    3,当前的marshaling context
    首先我们将object转换成Person

    Person person = (Person) value;
    接着,我们就可以开始输出数据了,首先我们创建一个叫做fullname的节点,并将person的名字传给他:

    writer.startNode("fullname"); 
    writer.setValue(person.getName()); 
    writer.endNode();

    呵呵~很简单吧,

    public void marshal(Object value, HierarchicalStreamWriter writer, 
                    MarshallingContext context) { 
            Person person = (Person) value; 
            writer.startNode("fullname"); 
            writer.setValue(person.getName()); 
            writer.endNode(); 
    }

    我们可以任意次数的调用start/end node方法,但需要记住,你必须在打开一个节点之后记住关闭它。一般来说,执行转换的操作在setValue方法调用时发生。
    下面,我们进入unmarshal方法,我们使用moveDown和moveUp方法在节点树层次中移动,所以,这里我们只需要简单的moveDown,得到值,再moveUp:

    Person person = new Person(); 
    reader.moveDown(); 
    person.setName(reader.getValue()); 
    reader.moveUp();

    最后,我们得到了一个这样的转换器:

    package com.thoughtworks.xstream.examples; 
    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 class PersonConverter implements Converter { 
     
            public boolean canConvert(Class clazz) { 
                    return clazz.equals(Person.class); 
            } 
     
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
                    Person person = (Person) value; 
                    writer.startNode("fullname"); 
                    writer.setValue(person.getName()); 
                    writer.endNode(); 
            } 
     
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    Person person = new Person(); 
                    reader.moveDown(); 
                    person.setName(reader.getValue()); 
                    reader.moveUp(); 
                    return person; 
            } 
    }

    接着,我们在我们的main方法中注册这个转化器:

    package com.thoughtworks.xstream.examples; 
    import com.thoughtworks.xstream.XStream; 
    import com.thoughtworks.xstream.io.xml.DomDriver; 
    public class PersonTest { 
            public static void main(String[] args) { 
                    Person person = new Person(); 
                    person.setName("Guilherme"); 
     
                    XStream xStream = new XStream(new DomDriver()); 
                    xStream.registerConverter(new PersonConverter()); 
                    xStream.alias("person", Person.class); 
                    System.out.println(xStream.toXML(person)); 
            } 
    }

    注意到我们怎么注册我们的转换器了么?只需要下面简单的一句:

    xStream.registerConverter(new PersonConverter());
    最终得到的结果是:

    <person>
      <fullname>Guilherme</fullname>
    </person>
    也许你会说:这只改变了我输出的树,我需要用它来转换数据。
    下面我们来尝试在person标签中创建一个叫做fullname的属性,而不是新创建一个节点:
    3,一种可选的方式:
    首先,为Person创建一个toString方法,里面包含了所有能用来重新创建一个Person实例的数据:

    package com.thoughtworks.xstream.examples; 
    public class Person { 
            private String name; 
            public String getName() { 
                    return name; 
            } 
            public void setName(String name) { 
                    this.name = name; 
            } 
            public String toString() { 
                    return getName(); 
            } 
    }

    现在,我们就能把我们的转化器简写为:

     

    package com.thoughtworks.xstream.examples; 
    import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; 
    public class PersonConverter extends AbstractSingleValueConverter { 
            public boolean canConvert(Class clazz) { 
                    return clazz.equals(Person.class); 
            } 
            public Object fromString(String str) { 
                    Person person = new Person(); 
                    person.setName(string); 
                    return person; 
            } 
    }

    现在,输出的XML也会变得更易读(为person创建别名person之后):

    <person>Guilherme</person>
    名字变成了一个内置的值,而不是一个单独的节点。
    4,转换Date:
    我们已经知道Converter接口是怎样工作的了,现在我们来创建一个使用Locale对象转换时间的转换器:
    在我们的转换器构造方法中,我们将传入一个Locale对象,该Locale对象会作为一个成员属性被转换器持有:

    package com.thoughtworks.xstream.examples; 
    import java.util.Locale; 
    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 class DateConverter implements Converter { 
            private Locale locale; 
            public DateConverter(Locale locale) { 
                    super(); 
                    this.locale = locale; 
            } 
            public boolean canConvert(Class clazz) { 
                    return false; 
            } 
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
            } 
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    return null; 
            } 
    }

    现在,让我们能转换任何继承了Calendar对象的类:

    public boolean canConvert(Class clazz) {
            return Calendar.class.isAssignableFrom(clazz);
    }
    首先,我们来将Calendar转换成本地化的字符串:首先我们把object转化成Calendar,得到Date对象,并使用DataFormatter来得到一个本地化的时间:

    public void marshal(Object value, HierarchicalStreamWriter writer, 
                    MarshallingContext context) { 
            Calendar calendar = (Calendar) value; 
            // grabs the date 
            Date date = calendar.getTime(); 
     
            // grabs the formatter 
            DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL, 
                            this.locale); 
            // formats and sets the value 
            writer.setValue(formatter.format(date)); 
    }

    另一方面,在unmarshall方法中,我们创建了一个GregorianCalendar,得到本地化的DataFormat实例,将字符串转换成Date对象,并赋值给GregorianCalendar。

    public Object unmarshal(HierarchicalStreamReader reader,
                    UnmarshallingContext context) {
            // creates the calendar
            GregorianCalendar calendar = new GregorianCalendar();
            // grabs the converter
            DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
                            this.locale);
            // parses the string and sets the time
            try {
                    calendar.setTime(formatter.parse(reader.getValue()));
            } catch (ParseException e) {
                    throw new ConversionException(e.getMessage(), e);
            }
            // returns the new object
            return calendar;
    }

    注意:
    1,记住一些DataFormat实现不是线程安全的,所以,不要让你的转换器持有DataFormat的引用
    2,在经过了保存和加载的过程后,该转换器可以将其他Calendar实现转换为GregorianCalendar。如果这不是你希望的,只需要修改canConvert方法,并在类型只有为GregorianCalendar的时候再返回true。
    现在,我们得到了下面这个转换器:

    package com.thoughtworks.xstream.examples; 
     
    import java.text.DateFormat; 
    import java.text.ParseException; 
    import java.util.Calendar; 
    import java.util.Date; 
    import java.util.GregorianCalendar; 
    import java.util.Locale; 
    import com.thoughtworks.xstream.converters.ConversionException; 
    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 class DateConverter implements Converter { 
            private Locale locale; 
            public DateConverter(Locale locale) { 
                    super(); 
                    this.locale = locale; 
            } 
            public boolean canConvert(Class clazz) { 
                    return Calendar.class.isAssignableFrom(clazz); 
            } 
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
                    Calendar calendar = (Calendar) value; 
                    Date date = calendar.getTime(); 
                    DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL, 
                                    this.locale); 
                    writer.setValue(formatter.format(date)); 
            } 
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    GregorianCalendar calendar = new GregorianCalendar(); 
                    DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL, 
                                    this.locale); 
                    try { 
                            calendar.setTime(formatter.parse(reader.getValue())); 
                    } catch (ParseException e) { 
                            throw new ConversionException(e.getMessage(), e); 
                    } 
                    return calendar; 
            } 
    }

    现在,我们来测试一下,创建一个main方法:
    1,创建一个calendar,
    2,创建XStream对象
    3,注册该转换器,并使用Brazilian Portuguese本地化对象
    4,将对象转化成XML
    代码如下:

    package com.thoughtworks.xstream.examples; 
    import java.util.Calendar; 
    import java.util.GregorianCalendar; 
    import java.util.Locale; 
    import com.thoughtworks.xstream.XStream; 
    import com.thoughtworks.xstream.io.xml.DomDriver; 
    public class DateTest { 
            public static void main(String[] args) { 
                    // grabs the current date from the virtual machine 
                    Calendar calendar = new GregorianCalendar(); 
                    // creates the xstream 
                    XStream xStream = new XStream(new DomDriver()); 
                    // brazilian portuguese locale 
                    xStream.registerConverter(new DateConverter(new Locale("pt", "br"))); 
                    // prints the result 
                    System.out.println(xStream.toXML(calendar)); 
            } 
    }

     可以得到类似如下的结果:

    <gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>
    注意,我们没有为GregorianCalendar创建任何别名,而gregorian-calendar就是默认的名字。
    下面我们来试试unmarshal 方法:

    // loads the calendar from the string
    Calendar loaded = (Calendar) xStream
                    .fromXML("<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>");
    然后打印出该日期:

    // prints using the system defined locale
    System.out.println(DateFormat.getDateInstance(DateFormat.SHORT).format(
                    loaded.getTime()));
    得到的结果为:

    2/10/06
    5,复杂的转换器:
    创建另一个例子:
    我们已经创建了两个对象了,现在把它们组合起来:

    package com.thoughtworks.xstream.examples; 
    public class Birthday { 
            private Person person; 
            private Calendar date; 
            public Person getPerson() { 
                    return person; 
            } 
            public void setPerson(Person person) { 
                    this.person = person; 
            } 
            public Calendar getDate() { 
                    return date; 
            } 
            public void setDate(Calendar date) { 
                    this.date = date; 
            } 
    }

     要转换该类,XStream一点问题都没有。这里,我们实现自己的转换器主要是为了验证,在这里,我们想重用我们刚才的PersonConverter和CalendarConverter。canConvert仍然很简单,不过这里,我们不需要再为每一个属性重新写转换方法了,我们只需要使用已经注册了的转换器来完成转换:

    package com.thoughtworks.xstream.examples; 
    import java.util.Calendar; 
    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 class BirthdayConverter implements Converter { 
            public boolean canConvert(Class clazz) { 
                    return Birthday.class == clazz; 
            } 
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
                    Birthday birthday = (Birthday)value; 
                    if (value.getPerson() != null) { 
                            writer.startNode("person"); 
                            context.convertAnother(value.getPerson()); 
                            writer.endNode(); 
                    } 
                    if (value.getDate() != null) { 
                            writer.startNode("birth"); 
                            context.convertAnother(value.getDate()); 
                            writer.endNode(); 
                    } 
            } 
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    Birthday birthday = new Birthday(); 
                    while (reader.hasMoreChildren()) { 
                            reader.moveDown(); 
                            if ("person".equals(reader.getNodeName())) { 
                                    Person person = (Person)context.convertAnother(birthday, Person.class); 
                                    birthday.setPerson(person); 
                            } else if ("birth".equals(reader.getNodeName())) { 
                                    Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class); 
                                    birthday.setDate(date); 
                            } 
                            reader.moveUp(); 
                    } 
                    return birthday; 
            } 
    }

     如果birthday实例能够确保不会出现null值,那么我们就可以去掉marshal和unmarshal方法中对null情况的判断,也不需要循环,而直接根据tag的名字进行解析:

    package com.thoughtworks.xstream.examples; 
     
    import java.util.Calendar; 
    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 class BirthdayConverter implements Converter { 
            public boolean canConvert(Class clazz) { 
                    return Birthday.class == clazz; 
            } 
            public void marshal(Object value, HierarchicalStreamWriter writer, 
                            MarshallingContext context) { 
                    Birthday birthday = (Birthday)value; 
                    writer.startNode("person"); 
                    context.convertAnother(value.getPerson()); 
                    writer.endNode(); 
                    writer.startNode("birth"); 
                    context.convertAnother(value.getDate()); 
                    writer.endNode(); 
            } 
            public Object unmarshal(HierarchicalStreamReader reader, 
                            UnmarshallingContext context) { 
                    Birthday birthday = new Birthday(); 
                    reader.moveDown(); 
                    Person person = (Person)context.convertAnother(birthday, Person.class); 
                    birthday.setPerson(person); 
                    reader.moveUp(); 
                    reader.moveDown(); 
                    Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class); 
                    birthday.setDate(date); 
                    reader.moveUp(); 
                    return birthday; 
            } 
    }
     
  • 评论 】 【收藏】 【 推荐给朋友 】 【字体: 】 【关闭
评论:共0条

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