jaxb xml to Bean 生成对象为值null

jaxb to Bean 生成对象为值null

事情处理结果

直接将命名空间给replace掉

xml.replace("xmlns=\"http://www.aaa.bb.ccc\"", "")

起因

因为系统对接需要,现在需要将一段xml解析出来,虽然可以使用dom方式去解析,但是总感觉很麻烦,想通过jaxb的这种方式,直接将xml映射到JavaBean上,通过get和set去取对应的值,感觉这样比较顺手,所以直接开干

同事不知道从哪借鉴(抄)过来一个工具类,代码如下

package net.wdm.tools.xml;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author heshengchao@qq.com
 * @since 2013-7-26 下午4:41:53
 */
public class XmlConvert {
	private static final Logger log = LoggerFactory.getLogger(XmlConvert.class);
	public static XmlConvert instance = new XmlConvert();

	private static final Map<Class<?>, Marshaller> JAXB_MARSHALL_MAP = Collections
			.synchronizedMap(new HashMap<Class<?>, Marshaller>());
	private static final Map<Class<?>, Unmarshaller> JAXB_UNMARSHALL_MAP = Collections
			.synchronizedMap(new HashMap<Class<?>, Unmarshaller>());

	/**
	 * @param xml
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <X> X toBean(String xml, Class<X> clazz) {
		try {
			JAXBContext context = JAXBContext.newInstance(clazz);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			StringReader sw = new StringReader(xml);
			return (X) unmarshaller.unmarshal(sw);

		} catch (Exception e) {
			log.warn("异常对象:" + xml);
			log.error(e.getMessage(), e);
			JAXB_UNMARSHALL_MAP.put(clazz, null);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public <X> X toBean(InputStream xmlStream, Class<X> clazz) {
		try {
			Unmarshaller msl = JAXB_UNMARSHALL_MAP.get(clazz);
			if (msl == null) {
				JAXBContext context = JAXBContext.newInstance(clazz);
				msl = context.createUnmarshaller();
				JAXB_UNMARSHALL_MAP.put(clazz, msl);
			}
			synchronized (msl) {
				return (X) msl.unmarshal(xmlStream);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			// 解决出现异常后,该信息一直出现的问题
			JAXB_UNMARSHALL_MAP.put(clazz, null);
		}
		return null;
	}

	/**
	 * @param bean
	 * @return
	 */
	public String toXML(Object bean) {
		if (bean == null) {
			log.error("传入对象为空!请检查程序。");
			return null;
		}
		try {
			Marshaller msl = JAXB_MARSHALL_MAP.get(bean.getClass());
			if (msl == null) {
				JAXBContext context = JAXBContext.newInstance(bean.getClass());
				msl = context.createMarshaller();
				msl.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
				JAXB_MARSHALL_MAP.put(bean.getClass(), msl);
			}

			StringWriter sw = new StringWriter();
			synchronized (msl) {
				msl.marshal(bean, sw);
			}
			return sw.toString();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			// 解决出现异常后,该信息一直出现的问题
			JAXB_MARSHALL_MAP.put(bean.getClass(), null);
		}
		return null;
	}

	/**
	 * @param bean
	 * @return
	 */
	public void toXML(Object bean, OutputStream out) {
		try {
			Marshaller msl = JAXB_MARSHALL_MAP.get(bean.getClass());
			if (msl == null) {
				JAXBContext context = JAXBContext.newInstance(bean.getClass());
				msl = context.createMarshaller();
				// 是否格式化生成的字符串
				msl.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

				JAXB_MARSHALL_MAP.put(bean.getClass(), msl);
			}
			synchronized (msl) {
				msl.marshal(bean, out);
			}
		} catch (JAXBException e) {
			log.error(e.getMessage(), e);
			// 解决出现异常后,该信息一直出现的问题
			JAXB_MARSHALL_MAP.put(bean.getClass(), null);
		}
	}

}

因为有public <X> X toBean(InputStream xmlStream, Class<X> clazz)这个方法,感觉toBean是个很容易的事情,事实上并没有这么简单

经过

首先,我有两个类

package com.wdm.pang.entity.xintong.IOrder;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "CEB312Message", namespace = "http://www.aaa.bb.ccc")
public class CEB312Message {

	@XmlElement(name = "OrderReturn")
	private OrderReturn orderReturn;

	public OrderReturn getOrderReturn() {
		return this.orderReturn;
	}

	public void setOrderReturn(OrderReturn orderReturn) {
		this.orderReturn = orderReturn;
	}

	@Override
	public String toString() {
		return "CEB312Message [orderReturn=" + orderReturn + "]";
	}

}
package com.wdm.pang.entity.xintong.IOrder;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "OrderReturn")
public class OrderReturn {

	@XmlElement(name = "guid")
	private String guid;

	@XmlElement(name = "ebpCode")
	private String ebpCode;

	@XmlElement(name = "ebcCode")
	private String ebcCode;

	@XmlElement(name = "orderNo")
	private String orderNo;

	@XmlElement(name = "returnStatus")
	private Integer returnStatus;

	@XmlElement(name = "returnTime")
	private String returnTime;

	@XmlElement(name = "returnInfo")
	private String returnInfo;

	public String getGuid() {
		return this.guid;
	}

	public void setGuid(String guid) {
		this.guid = guid;
	}

	public String getEbpCode() {
		return this.ebpCode;
	}

	public void setEbpCode(String ebpCode) {
		this.ebpCode = ebpCode;
	}

	public String getEbcCode() {
		return this.ebcCode;
	}

	public void setEbcCode(String ebcCode) {
		this.ebcCode = ebcCode;
	}

	public String getOrderNo() {
		return this.orderNo;
	}

	public void setOrderNo(String orderNo) {
		this.orderNo = orderNo;
	}

	public Integer getReturnStatus() {
		return returnStatus;
	}

	public void setReturnStatus(Integer returnStatus) {
		this.returnStatus = returnStatus;
	}

	public String getReturnTime() {
		return this.returnTime;
	}

	public void setReturnTime(String returnTime) {
		this.returnTime = returnTime;
	}

	public String getReturnInfo() {
		return this.returnInfo;
	}

	public void setReturnInfo(String returnInfo) {
		this.returnInfo = returnInfo;
	}

	@Override
	public String toString() {
		return "OrderReturn [guid=" + guid + ", ebpCode=" + ebpCode + ", ebcCode=" + ebcCode + ", orderNo=" + orderNo
				+ ", returnStatus=" + returnStatus + ", returnTime=" + returnTime + ", returnInfo=" + returnInfo + "]";
	}

}

然后我有一个字符串:

<?xml version="1.0" encoding="UTF-8" xmlns="http://www.aaa.bb.ccc" ? >
<OrderReturn>
    <guid>83B32909-6855-46BD-ACED-B153BC252446</guid>
    <ebpCode>1</ebpCode>
    <ebcCode>1</ebcCode>
    <orderNo>1</orderNo>
    <returnStatus>5</returnStatus>
    <returnTime>20180926165332552</returnTime>
    <returnInfo>预处理成功</returnInfo>
</OrderReturn>

按照我正常的思路,只需要这样CEB312Message message = XmlConvert.instance.toBean(xml, CEB312Message.class);message对象里面就会有值,然而并不是,System.out.println(message );的结果只是CEB312Message [orderReturn=null],那么问题就来了,究竟是什么原因导致的呢?

抱着疑问,我把原来的类上的注解@XmlRootElement(name = "CEB312Message", namespace = "http://www.aaa.bb.ccc")中的命名空间删除,直接改为@XmlRootElement(name = "CEB312Message"),然后就可以了么?不,事情并没有那么简单,报错了。。。

javax.xml.bind.UnmarshalException: 意外的元素 (uri:"http://www.aaa.bb.ccc", local:"CEB312Message")。所需元素为<{}CEB312Message>,<{}OrderReturn>
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3132)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:852)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
	at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
	at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
	at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:214)
	at com.wdm.pang.controller.entity.dto.Test.toBean(Test.java:72)
	at com.wdm.pang.controller.entity.dto.Test.main(Test.java:41)

那怎么办呢,改回去吧。

我又在想,难道是我的JavaBean注解没对?

那我从Bean生成一个xml对比一下看看效果先,于是乎一把梭

		CEB312Message ceb312Message = new CEB312Message();
		CEB312Message stringToObject = XmlConvert.instance.toBean(back, CEB312Message.class);
		System.out.println(stringToObject);
		OrderReturn orderReturn = new OrderReturn();
		orderReturn.setGuid("83B32909-6855-46BD-ACED-B153BC252446");
		orderReturn.setEbcCode("1");
		orderReturn.setEbpCode("1");
		orderReturn.setOrderNo("1");
		orderReturn.setReturnInfo("预处理成功");
		orderReturn.setReturnStatus(5);
		orderReturn.setReturnTime("20180926165332552");
		ceb312Message.setOrderReturn(orderReturn);
		String xml = XmlConvert.instance.toXML(ceb312Message);
		System.out.println(xml);

-----------------------输出结果-----------------------------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:CEB312Message xmlns:ns2="http://www.aaa.bb.ccc">
    <OrderReturn>
        <guid>83B32909-6855-46BD-ACED-B153BC252446</guid>
        <ebpCode>1</ebpCode>
        <ebcCode>1</ebcCode>
        <orderNo>1</orderNo>
        <returnStatus>5</returnStatus>
        <returnTime>20180926165332552</returnTime>
        <returnInfo>预处理成功</returnInfo>
    </OrderReturn>
</ns2:CEB312Message>

那么问题又来了,这个ns2:是个什么鬼,好像我也没有什么地方写了这个东西啊,真是头大,一顿疯狂的百度,然后找到下面的这些资料:

这些资料都写的很好,非常有效的解决了ns2:这个前缀问题,然而我的目的并不是要生成xml,我的初衷是要去解析xml到javaBean
所以,我又回到了正题,既然我是因为namespace的问题导致的解析不正确问题,那我可不可以不要这个namespace,直接删掉试试,于是就有了如下代码:

CEB312Message ceb312Message = XmlConvert.instance.toBean(xml.replace("xmlns=\"http://www.chinaport.gov.cn/ceb\"", ""),CEB312Message.class);

System.out.println(ceb312Message);

----------------------输出结果---------------------------
CEB312Message [orderReturn=OrderReturn [guid=83B32909-6855-46BD-ACED-B153BC252446, ebpCode=1, ebcCode=1, orderNo=1, returnStatus=5, returnTime=20180926165332552, returnInfo=预处理成功]]

然后居然有值了,emmmm简直是。


附上Maven引用

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.2.11</version>
</dependency>

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.0.1</version>
</dependency>

虽然这个方法太草率了,先将就用着,毕竟时间紧任务重,如果有大佬做过,并且很好的解决了这个问题,欢迎留言告诉我,3Q

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值