xstream使用的第二个小问题

本文探讨了XStream在将XML转换为Java对象时出现的缓存问题,特别是当两个不同的Java对象具有相同的XML结构时,由于XStream内部的缓存机制导致的类型转换错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前说过一个xstream使用过程中遇到的一个小问题,链接: https://my.oschina.net/110NotFound/blog/2987017

这次又遇到一个,情况是这样的:

当在生产环境使用xstream进行解析xml转换为java对象的时候有一个缓存问题, 如果有两个不相干的接口,这两个接口唯一的共同点就是使用了xstream解析返回结果,且巧合的是两个接口的返回结果xml格式一模一样。

xml结果格式如下:

<response><success>true</success></response>

这两个接口都定义了一个bean,且结构一样,A对象定义如下:

@XStreamAliasType(value="response")
public class Response1 {
   
    @XStreamAsAttribute
    private String success;

    @XStreamAsAttribute
    private String errorMsg;

    public String getSuccess() {
        return success;
    }

    public void setSuccess(String success) {
        this.success = success;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
}

B对象定义如下:

@XStreamAliasType(value="response")
public class Response2 {
   
    @XStreamAsAttribute
    private String success;

    @XStreamAsAttribute
    private String errorMsg;

    public String getSuccess() {
        return success;
    }

    public void setSuccess(String success) {
        this.success = success;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
}

解析的操作大致如下:

public static void main(String[] args) throws InterruptedException {
    String resp = "<response><success>true</success></response>";
    Response1 response1 = (Response1) XmlUtil.xml2Object(resp, new Class[] { Response1.class });
    String a = response1.getSuccess();
    Object object = XmlUtil.xml2Object(resp, new Class[] { Response2.class });
    Response2 response2 = (Response2) object;
    String b = response2.getSuccess();
    System.out.println(a+ " : " +b);
}

xmlUtil:

public class XmlUtil {
	public static Object xml2Object(String inputXml, Class<?>[] types){
		if (StringUtils.isBlank(inputXml)) {
			return null;
		}
		XStream xstream = XStreamUtil.getInstance();
		xstream.processAnnotations(types);
		return xstream.fromXML(inputXml);
	}
}

当A对象和B对象都在从xml解析到对象的时候会引发一个错误:

com.xxx.Response2 cannot be cast to com.xxx.Response1

根本原因: XStream本身在进行讲xml转换到对象的时候,对每一次操作的类都进行了对象缓存,存储在一个map里面,这个map的key是你要解析的xml的头结点名字,在这里就是response, 当解析xml的时候会读取这个map里面的key为response的value,这样可以直接在缓存里面拿到class,达到解析速度更快。 这就是报错的根本原因。

xstream里的com.thoughtworks.xstream.mapper.CachingMapper类源码是这样定义的:

private transient Map realClassCache;

public Class realClass(String elementName) {
    Object cached = realClassCache.get(elementName);
    if (cached != null) {
        if (cached instanceof Class) {
            return (Class)cached;
        }
        throw (XStreamException)cached;
    }

    try {
        Class result = super.realClass(elementName);
        realClassCache.put(elementName, result);
        return result;
    } catch (ForbiddenClassException e) {
        realClassCache.put(elementName, e);
        throw e;
    } catch (CannotResolveClassException e) {
        realClassCache.put(elementName, e);
        throw e;
    }
}

可以看出使用 elementName 做缓存,这一点我个人觉得还是有待商榷,为了性能埋下了一个坑。

转载于:https://my.oschina.net/110NotFound/blog/3031869

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值