xstream 指定序列化的顺序

xstream 指定序列化的顺序

需求:在使用xstream转化Javabean->xml的过程中,有时候,我们需要指定xml化的顺序,xstream默认的是按字符定义的顺序来xml化的,
但是,有的时候如果我们使用的继承某些class,而无法改变的时候,这就非常难办了。

解决方案一:

官方给了一个类:通过 com.thoughtworks.xstream.converters.reflection.FieldDictionary.来实现指定xml化的顺序字典,
可以参考例子地址

public void testSortsFieldOrderWithArray() {

        SortableFieldKeySorter sorter = new SortableFieldKeySorter();
        sorter.registerFieldOrder(MommyBear.class,
                new String[]{"absde", "absese", "accsed", "money"});

        XStream xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(sorter)));
        xstream.alias("mommy", MommyBear.class);
        MommyBear root = new MommyBear();
        root.absde = "ccc";
        root.absese = "bbb";
        root.accsed = "aaa";
//        root.money = "12";
        System.out.println(xstream.toXML(root));
    }

    public static class MommyBear implements Serializable {
        String absde;
        String absese;
        String accsed;
        String money;
    }

然而通过这个方式有缺点,那就是如果有N个属性成员,如果有没有指定的话,那么会报错。而且不具备通用性,如果有M个类需要指定的话,那么
工作量也是非常大的。
为了解决这个问题,我们可以参考Stack Overflow的这个解决方案

解决方案二:

  1. 定义一个声明:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface XMLSequence {
    String[] value();
}
  1. 生成一个FieldKeySorter的实现类,用来注入xstream实例中
public class SequenceFieldKeySorter implements FieldKeySorter {
    @Override
    public Map sort(final Class type, final Map keyedByFieldKey) {
        Annotation sequence = type.getAnnotation(XMLSequence.class);
        if (sequence != null) {
            final String[] fieldsOrder = ((XMLSequence) sequence).value();
            Map result = new LinkedHashMap();
            Set<Map.Entry<FieldKey, Field>> fields = keyedByFieldKey.entrySet();
            for (String fieldName : fieldsOrder) {
                if (fieldName != null) {
                    for (Map.Entry<FieldKey, Field> fieldEntry : fields) {
                        if
                                (fieldName.equals(fieldEntry.getKey().getFieldName())) {
                            result.put(fieldEntry.getKey(),
                                    fieldEntry.getValue());
                        }
                    }
                }
            }
            return result;
        } else {
            return keyedByFieldKey;
        }
    }
}
  1. 把fieldSorter 的实现类注入到xStream中,代码如下:
  XStream xStream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(new PartialSeqFieldKeySorter())));

在方案而中,如果有了XmlSequence声明,如下:

@Setter
@Getter
@XMLSequence({"imID", "zipCode"})
public class Buyer {
    private String email;
    private String zipCode;
    private String address;
    private String imID;
    private String name;
    private String phone;
    private String mobile;
}

如果你声明中只定义了N-x个的话,那么,剩下的都不会被xml化,结果如下(address没有被xml化):

<buyer>
  <imID>imId001</imID>
  <zipCode>00001</zipCode>
</buyer>

这是个问题,我们需要声明所有的属性,对于多属性成员来说,这是不可取的。为了
解决这个问题,我们重新实现SequenceFieldKeySorter中的 public Map sort(Class type, Map keyedByFieldKey) 方法,代码如下:

	@Override
    public Map sort(Class type, Map keyedByFieldKey) {
        Annotation sequence = type.getAnnotation(XMLSequence.class);
        if (sequence != null) {
            final String[] fieldsOrder = ((XMLSequence) sequence).value();
            Map<FieldKey, Field> custom = new LinkedHashMap<>();
            Map<FieldKey, Field> notCustom = new LinkedHashMap<>();
            Set<Map.Entry<FieldKey, Field>> fields = keyedByFieldKey.entrySet();
            for (String fieldName : fieldsOrder) {
                if (fieldName != null) {
                    for (Map.Entry<FieldKey, Field> fieldEntry : fields) {
                        if (fieldName.equals(fieldEntry.getKey().getFieldName())) {
                            custom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        } else {
                            notCustom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        }
                    }
                }
            }
            custom.putAll(notCustom);
            return custom;
        } else {
            return keyedByFieldKey;
        }
    }

两者的区别在于这里我们实现了如果没有声明的,我们也加进返回结果中了

for (Map.Entry<FieldKey, Field> fieldEntry : fields) {
                        if (fieldName.equals(fieldEntry.getKey().getFieldName())) {
                            custom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        } else {
                            notCustom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        }
                    }
                    //没有定义的添加到结果中
                     custom.putAll(notCustom);
                                return custom;

重新定义一个类:

public class PartialSeqFieldKeySorter implements FieldKeySorter {
    @Override
    public Map sort(Class type, Map keyedByFieldKey) {
        Annotation sequence = type.getAnnotation(XMLSequence.class);
        if (sequence != null) {
            final String[] fieldsOrder = ((XMLSequence) sequence).value();
            Map<FieldKey, Field> custom = new LinkedHashMap<>();
            Map<FieldKey, Field> notCustom = new LinkedHashMap<>();
            Set<Map.Entry<FieldKey, Field>> fields = keyedByFieldKey.entrySet();
            for (String fieldName : fieldsOrder) {
                if (fieldName != null) {
                    for (Map.Entry<FieldKey, Field> fieldEntry : fields) {
                        if (fieldName.equals(fieldEntry.getKey().getFieldName())) {
                            custom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        } else {
                            notCustom.put(fieldEntry.getKey(), fieldEntry.getValue());
                        }
                    }
                }
            }
            custom.putAll(notCustom);
            return custom;
        } else {
            return keyedByFieldKey;
        }
    }
}

这样我们就可以只定义自己需要的属性成员就可以了,不改变上面Buyer.class的声明,这里我们可以生成所有的不为空的成员

<buyer>
  <imID>imId001</imID>
  <zipCode>00001</zipCode>
  <address>sh.cn</address>
</buyer>

结果正好!

完整代码如下代码
测试类参考测试代码

XStream是一种Java库,它可以将Java对象序列化为XML格式,并且还可以将XML格式反序列化Java对象。XStream可以非常方便地将Java对象转换为XML格式的字符串,也可以将XML格式的字符串转换为Java对象。XStream的使用非常简单,只需要创建一个XStream对象,然后调用toXML()方法将Java对象序列化为XML格式的字符串,或者调用fromXML()方法将XML格式的字符串反序列化Java对象。 下面是一个简单的示例,演示如何使用XStreamJava对象序列化为XML格式的字符串: ``` import com.thoughtworks.xstream.XStream; public class Person { private String name; private int age; // 省略getter和setter方法 public static void main(String[] args) { Person person = new Person(); person.setName("张三"); person.setAge(25); XStream xstream = new XStream(); String xml = xstream.toXML(person); System.out.println(xml); } } ``` 在上面的代码中,我们创建了一个Person对象,并设置了name和age属性的值。然后,我们创建了一个XStream对象,并调用toXML()方法将Person对象序列化为XML格式的字符串。最后,我们将序列化后的字符串打印出来。 输出结果如下: ``` <person> <name>张三</name> <age>25</age> </person> ``` 可以看到,XStreamJava对象序列化为了XML格式的字符串,并且为每个属性添加了相应的XML标签。在这个例子中,我们只有两个属性,因此只有两个XML标签。如果有更多的属性,XStream会为每个属性添加相应的XML标签。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值