解决方案(三)— 使用XStream解析Xml到JavaBean,保持属性默认值

使用场景

在Java开发中,有时我们需要自定义Xml,并使用常用的解析器XStream将Xml字符串InputStreamFile,解析成JavaBean对象。但是,有些时候,XML的标签属性,我们不需要额外赋值,它们通常只需要保持默认值。例如:

  • JavaBean类
@XStreamAlias("controllers")
public class ControllerGenerator {
	
	@XStreamAsAttribute
	private  String targetProject;
	
	@XStreamAsAttribute
	private  String targetFolder="src/main/java";
	
	@XStreamAsAttribute
	private  String targetPackage;
   
    /**
	 * ......
	 */
}
  • 对应XML
<controllers targetProject="kuaiban-platform"  targetPackage="kuaiban.platform.controller">
    /**
	 * ......
	 */
</controllers>

很显然,在XML中我们并没有直接定义属性 targetFolder 的值,而是希望它能够保持 Java类 中定义的初始值 “src/main/java”

然而,很遗憾,默认情况下,XStream并不支持这种操作。


转换器@XStreamConverter

    @XStreamAsAttribute
	@XStreamConverter(xxxConverter.class)
	private  String targetFolder="src/main/java";

首先想到的就是,实现 ConverterMatcher 接口,自定义一个转换器 xxxConverter

如果,是 BeanToXml@XStreamConverter将会很好的起到作用。
然而,很不幸,我们需要的是 XmlToBean,其工作原理,实际上就是解析XML中的字节码,而后进行处理(无非是顺序判断循环)。
既然,我们的XML内容中根本不包含 targetFolder这个字符串内容,那么程序自然也无法针对性的作做处理,属性targetFolder没有被处理,相应的,它的注解**@XStreamConverter(xxxConverter.class),也不可能被处理,所以在这里转换器 @XStreamConverter失效**。


原理

首先我们要来看一下,XStream最终构造函数

XStream xstream = new XStream(
        ReflectionProvider reflectionProvider, HierarchicalStreamDriver driver,
        ClassLoaderReference classLoaderReference, Mapper mapper, ConverterLookup converterLookup,
        ConverterRegistry converterRegistry);

ReflectionProvider 是参数之一,常见实现包含如下:

SunUnsafeReflectionProvider

  • XStream 缺省反射提供器,继承SunLimitedUnsafeReflectionProvider的**newInstance(Class)**调用 sun.misc.Unsafenative allocateInstance(Class) 本地方法为目标类分配实例属性值 **默认**为系统初始值 0falsenull

PureJavaReflectionProvider

  • 纯正的java反射提供器,实现接口ReflectionProvidernewInstance(Class)
    调用 java.lang.reflect.ConstructornewInstance(Class) java反射方法为目标类创建实例属性值自定义初始值用来保证反序列化的时候,使用 javaBean 中的默认值来表示 XML中没有显示指明的字段。
  • 但是其中的 writeField(Object,String,Object,Class)方法完全依照 reader 的值向实例中写入如果有特殊要求,请复写该方法。

解决方式

FieldDefaultValueProvider —— 自定义反射提供器

  • 继承 PureJavaReflectionProvider复写其中的 writeField(Object,String,Object,Class)方法 为reader去除首尾的space
  • 如果值为空白字符串取消注入,使用 javaBean中属性的默认值

实现代码:

public class FieldDefaultValueProvider extends PureJavaReflectionProvider {  
    /**
     * @param object 目标类的实例
     * @param fieldName XML中显示指明的字段
     * @param definedIn 父类或者类本身
     */
	@Override  
    public void writeField(Object object, String fieldName, Object value, Class definedIn) {
        Field field = fieldDictionary.field(object.getClass(), fieldName, definedIn);//返回存在于xml中的字段  
        validateFieldAccess(field);//验证字段可以被访问 
        try {  
            if (value instanceof String) {
				String trim = ((String)value).trim();//字符串首尾去空
				if(trim.length()==0)//如果是空字符串,则不做赋值,使用默认初始值
					return;
				field.set(object,trim);  
			}else{
				field.set(object, value);  
			}
        } catch (IllegalArgumentException e) {  
            throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e);  
        } catch (IllegalAccessException e) {  
            throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e);  
        }  
    }  
} 

使用方式:

public static <T> T  toBeanFromFile(InputStream in,Class<T> cls) throws Exception{
            XStream xstream=new XStream(new FieldDefaultValueProvider(),new Xpp3Driver());//默认支持DTD
            xstream.processAnnotations(cls);
            return (T)xstream.fromXML(in);        
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用XStream库实现XML与对象之间的互转可以通过以下步骤完成: 1. 引入XStream库的依赖:在你的项目中引入XStream库的依赖,可以参考我之前提供的Maven和Gradle配置。 2. 定义Java类:创建一个Java类来表示你的对象,并使用XStream提供的注解来指定XML元素和属性与Java类的映射关系。例如: ```java import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("person") public class Person { private String name; private int age; // 省略构造函数、getter和setter方法 // ... } ``` 3. 将对象转换为XML使用XStream将Java对象转换为XML字符串。示例如下: ```java import com.thoughtworks.xstream.XStream; public class Main { public static void main(String[] args) { // 创建XStream实例 XStream xStream = new XStream(); // 设置类别名,用于与XML元素进行映射 xStream.alias("person", Person.class); // 创建一个Person对象 Person person = new Person(); person.setName("John"); person.setAge(30); // 将Person对象转换为XML字符串 String xml = xStream.toXML(person); // 输出XML字符串 System.out.println(xml); } } ``` 以上代码将输出以下XML字符串: ```xml <person> <name>John</name> <age>30</age> </person> ``` 4. 将XML转换为对象:使用XStreamXML字符串转换回Java对象。示例如下: ```java import com.thoughtworks.xstream.XStream; public class Main { public static void main(String[] args) { // 创建XStream实例 XStream xStream = new XStream(); // 设置类别名,用于与XML元素进行映射 xStream.alias("person", Person.class); // XML字符串 String xml = "<person><name>John</name><age>30</age></person>"; // 将XML转换为Person对象 Person person = (Person) xStream.fromXML(xml); // 输出Person对象的属性 System.out.println("Name: " + person.getName()); System.out.println("Age: " + person.getAge()); } } ``` 以上代码将输出: ``` Name: John Age: 30 ``` 通过以上步骤,你可以使用XStream实现XML与对象之间的互转。你可以根据具体的需求对Java类和XML结构进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值