很多老系统,特别是C++的系统,可能数据结构采用的xml。xml对java来说没有什么,但是C++来说,可能还有个顺序问题,毕竟c++没有那么多通用类库。
2 xstream
先说依赖,我本来不想升级,但是有个问题卡者就给升了,虽然升了并没有解决我的问题。
xml
<!-- xstream 升级到1.4.18后 依赖的jar -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
<dependency>
<groupId>xmlpull</groupId>
<artifactId>xmlpull</artifactId>
<version>1.1.3.4d_b4_min</version>
</dependency>
<dependency>
<groupId>xpp3</groupId>
<artifactId>xpp3_min</artifactId>
<version>1.1.4c</version>
</dependency>
2.1 双下划线问题
看下面注释
java
public static String toXml(Object obj) {
// XStream xstream = new XStream(new DomDriver(encoding));
XStream xstream = new XStream(new Xpp3Driver(new NoNameCoder())); // 解决xml双下划线的问题
// XStream xstream=new XStream(new DomDriver()); //直接用jaxp dom来解释
// XStream xstream=new XStream(new DomDriver("utf-8")); //指定编码解析器,直接用jaxp dom来解释
//如果没有这句,xml中的根元素会是<包.类名>;或者说:注解根本就没生效,所以的元素名就是类的属性
xstream.processAnnotations(obj.getClass()); //通过注解方式的,一定要有这句话
return xstream.toXML(obj);
}
2.2 复杂对象转换的问题
一般的复杂结构还不会有问题,但是老式的默认却不行,很奇怪。
跟踪代码调试,发现有一个被解释为String类型了
看看我的结构
第一层
java
@Data
@XStreamAlias("business")
public class ReqInvoiceIssue026Bean extends BusinessBean implements RequestBean {
/**
*
*/
private static final long serialVersionUID = 279889115759202804L;
@XStreamAlias("REQUEST_COMMON_FPKJ")
private ReqInvoiceIssueBody026Bean body;
第二层
java
@Data
@XStreamAlias("REQUEST_COMMON_FPKJ")
public class ReqInvoiceIssueBody026Bean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 7806868114280462342L;
@XStreamAlias("class")
@XStreamAsAttribute
private String cls = "REQUEST_COMMON_FPKJ";
@XStreamAlias("COMMON_FPKJ_FPT")
private ReqInvoiceIssueFyxm026Bean fyxm;
@XStreamAlias("COMMON_FPKJ_XMXXS")
private ReqInvoiceIssueFyxmGroup026Bean xmxxs;
}
第三层,到了第三层的时候,解析失败。
java
@Data
@XStreamAlias("COMMON_FPKJ_XMXXS")
public class ReqInvoiceIssueFyxmGroup026Bean implements Serializable {
@XStreamAlias("class")
@XStreamAsAttribute
private String cls = "COMMON_FPKJ_XMXX";
@XStreamAsAttribute
private Integer size;
@XStreamImplicit(itemFieldName = "COMMON_FPKJ_XMXX")
private List<ReqInvoiceIssueFyxmGroupXmxx026Bean> xmxx;
第四层
java
@Data
public class ReqInvoiceIssueFyxmGroupXmxx026Bean implements Serializable {
异常信息如下:
java
com.thoughtworks.xstream.converters.ConversionException:
---- Debugging information ----
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : COMMON_FPKJ_XMXX
class : com.whty.einv.sks.model.params.req.body.ReqInvoiceIssueBody026Bean
required-type : com.whty.einv.sks.model.params.req.body.ReqInvoiceIssueBody026Bean
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /business/REQUEST_COMMON_FPKJ/COMMON_FPKJ_XMXXS
line number : 32
class[1] : com.whty.einv.sks.model.params.req.business.ReqInvoiceIssue026Bean
required-type[1] : com.whty.einv.sks.model.params.req.business.ReqInvoiceIssue026Bean
version : 1.4.20
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:81)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:68)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:74)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:68)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:52)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:136)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1464)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1441)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1321)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1312)
at com.whty.einv.sks.model.util.XmlUtil.toBean(XmlUtil.java:53)
at com.whty.einv.sks.model.test.TestJavaToXml.toBean(TestJavaToXml.java:108)
at com.whty.einv.sks.model.test.TestJavaToXml.test10_026(TestJavaToXml.java:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: COMMON_FPKJ_XMXX
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:81)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:79)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:74)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:71)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:420)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:74)
... 40 more
Process finished with exit code -1
经过多轮尝试,问题的根源在@XStreamAlias("class")
,这个class
是不是跟什么冲突了。
找到问题了,问题也将迎刃而解。
java
//注意:不是new Xstream(); 否则报错:java.lang.NoClassDefFoundError: org/xmlpull/v1/XmlPullParserFactory
// XStream xstream = new XStream();
XStream xstream = new XStream(new Xpp3Driver(new NoNameCoder())); // 解决xml双下划线的问题
// 去掉class属性
xstream.aliasSystemAttribute(null,"class");
//解决XStream的安全警告
xstream.addPermission(AnyTypePermission.ANY);
// XStream.setupDefaultSecurity(xstream);
xstream.allowTypes(new Class[]{cls});
//扫描注解
xstream.processAnnotations(cls);
T obj = (T) xstream.fromXML(xmlStr);
return obj;
.1 jibx实现
先看依赖,使用这个技术比较麻烦一点,就是再打包的时候要执行mvn jibx:bind
xml
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-run</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-extras</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jibx</groupId>
<artifactId>jibx-tools</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
再看打包
xml
<build>
<plugins>
<!-- 源码插件 -->
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jibx</groupId>
<artifactId>jibx-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<schemaBindingDirectory>src/main/resources</schemaBindingDirectory>
<includeSchemaBindings>
<!-- 每次执行前需要先mvn clean compile test-compile或手动删除Jibx生成的文件,再执行mvn jibx:bind,有相同类名时,一次性会执行失败 -->
<!-- jibx生成的所有类文件会位于第一个生成的类的同目录下,分开执行可以在不同的文件夹生成对应类 -->
<includeSchemaBindings>binding/request/*-binding.xml</includeSchemaBindings>
<includeSchemaBindings>binding/response/*-binding.xml</includeSchemaBindings>
</includeSchemaBindings>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<goals>
<goal>bind</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
使用如下
java
/**
* obj转xml
*
* @param obj
* @param indent 格式化缩进
* @return String
* @throws JiBXException
*/
public static String toXml(Object obj, int indent) throws JiBXException {
IBindingFactory bfact = BindingDirectory.getFactory(obj.getClass());
IMarshallingContext mctx = bfact.createMarshallingContext();
mctx.setIndent(indent);
StringWriter writer = new StringWriter();
mctx.marshalDocument(obj, encoding, null, writer);
return writer.toString();
}
/**
* xml转obj
*
* @param xml
* @param clazz
* @return
* @throws JiBXException
*/
public static <T> T fromXml(String xml, Class<T> clazz) throws JiBXException {
IBindingFactory bfact = BindingDirectory.getFactory(clazz);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
Object obj = uctx.unmarshalDocument(new StringReader(xml), null);
return clazz.cast(obj);
}