XSteam低版本xml转bean多余字段报错问题
对于一些老项目,可能会用到一些低版本的工具,例如XStream就是一款报文与实体类转换的工具,我们之前的报文为xml格式的,正常使用没有问题,如果多了某个字段是bean里面没有的,那么就会报错,对于此问题,特意进行了学习,并记录一下。
多余字段报错
举例说明:现有消费者类:
public class Consumer {
private String id;
private String userName;
private String password;
private String age;
private String address;
private String sex;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Consumer{" +
"id='" + id + '\'' +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", age='" + age + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
转换方法:
public Customer xmlToBean(String customerXml) {
XStream xs = new XStream(new DomDriver());
xs.alias("Customer",Customer.class);
Customer customer = (Customer)xs.fromXml(customerXml);
return customer;
}
如果报文的字段均在Customer类里,则正常转换,如果对接方多传了字段,则会报错,例如我们多传一个字段test
Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: test : test : test : test
---- Debugging information ----
message : test : test
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : test : test
class : com.example.websocketdemo1.vo.Consumer
required-type : com.example.websocketdemo1.vo.Consumer
path : /Consumer/test
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:89)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:63)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:76)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:60)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:137)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:33)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:923)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:909)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:853)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:845)
at com.example.websocketdemo1.proxy.MainTest.main(MainTest.java:44)
如果是高版本的XStream,可以使用ignoreUnknownElements() 方法,忽略多余的字段,如果是低版本的XStream则没有此方法,需要我们重写XStream的 protected MapperWrapper wrapMapper(MapperWrapper next) 方法,例如我们可以新建一个类,继承XStream:
public class XStreamOmitUnknownField extends XStream {
public XStreamOmitUnknownField() {
super();
}
public XStreamOmitUnknownField(DomDriver domDriver) {
super(domDriver);
}
@Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
@Override
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super.shouldSerializeMember(definedIn, fieldName);
}
};
}
}
也可以直接在 new XStream时重写,例如:
XStream xStream = new XStream() {
@Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
@Override
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super.shouldSerializeMember(definedIn, fieldName);
}
};
}
};
xStream.fromXml(customerXml);
以上两种均可以解决多余字段报错问题。
转xml时包含包名的问题解决
将实体类转换为xml,有时会多一些我们不想要的包名
例如:
<com.example.websocketdemo1.vo.ConsumerVo>
<id>213</id>
<address>中国</address>
<test>sdf</test>
</com.example.websocketdemo1.vo.ConsumerVo>
如果想要将包名去掉,可以设置别名:
例如:
XStream xStream = new XStream() {
@Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
@Override
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super.shouldSerializeMember(definedIn, fieldName);
}
};
}
};
ConsumerVo consumerVo = new ConsumerVo();
consumerVo.setTest("sdf");
consumerVo.setId("213");
consumerVo.setAddress("中国");
xStream.alias("ConsumerVo",ConsumerVo.class);
String s = xStream.toXML(consumerVo);
System.out.println(s);
这样执行的结果就是:
<ConsumerVo>
<id>213</id>
<address>中国</address>
<test>sdf</test>
</ConsumerVo>
这样就去掉了包名,只保留我们想要的。