JAXB - xml与对象的转换

在与第三方进行数据交互时,对方要求以 xml 格式进行数据传输,如果自己去拼接和解析报文,确实可以达到效果,不过这样不仅不够优雅并且还十分繁琐,费时费力。查找资料发现 javax 包里有对 xml 的支持。

常用注解

@XmlRootElement
标识这个类或枚举类型是根元素,映射到 XML 元素中。JAXB 中的注解, 作用在类上。

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

@XmlElement
将java对象的属性映射为xml的节点。将没有get方法/set方法的属性映射到XML,作用在字段或方法。

@XmlElement(name = "ServiceInfo", type = ServiceInfo.class)
List<ServiceInfo> ServiceInfo;

@XmlAttribute
將 java 对象的属性映射为 xml 的节点的属性。
例如:将 desc 标识为 < Attr> 节点的属性

@XmlAccessorType(XmlAccessType.FIELD)
public class Attr {

    @XmlAttribute(name = "Desc")
    String desc;

    @XmlElement(name = "AttrName")
    String attrName;

    @XmlElement(name = "AttrCode")
    String attrCode;
}
<Attr Desc="描述">
   <AttrName>材料名称</AttrName>
   <AttrCode>材料编码</AttrCode>
</Attr>

@XmlAccessorType
控制默认情况下是否对字段或 Javabean 属性进行系列化。

默认规则
如果不存在 @XmlAccessorType,使用@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)

可能值:
FIELD: 绑定类中的(每个,没有get方法/set方法的属性也可以)非静态、非瞬态字段将会自动绑定映射到 XML,除非由 XmlTransient 注释。

NONE: 所有字段或属性都不能绑定到 XML,除非使用一些 JAXB 注释专门对它们进行注释。

PROPERTY: 绑定类中的(每个,只有有get方法/set方法的属性才可以)自动绑定映射到 XML,除非由 XmlTransient 注释。

PUBLIC_MEMBER:每个公共获取方法/设置方法对和每个公共字段将会自动绑定到 XML,除非由 XmlTransient 注释。

@XmlTransient(非瞬态)
用于标示在由Java对象映射XML时,忽略此属性,在生成的XML文件中将不出现此元素。

使用案例

以如下 xml 文本为例

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Services>
    <Total>1000</Total>
    <ServiceInfo>
        <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>
        <ServiceName>测试</ServiceName>
        <ServiceType>1</ServiceType>
        <State>I</State>
        <PromiseDay>1</PromiseDay>
        <UpdateTime>2023-03-29 08:38:46</UpdateTime>
        <Attrs>
            <Attr>
                <AttrName>材料名称</AttrName>
                <AttrCode>材料编码</AttrCode>
            </Attr>
        </Attrs>
    </ServiceInfo>
    <ServiceInfo>
        <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>
        <ServiceName>测试2</ServiceName>
        <ServiceType>1</ServiceType>
        <State>I</State>
        <PromiseDay>1</PromiseDay>
        <UpdateTime>2023-03-29 08:38:46</UpdateTime>
        <Attrs>
            <Attr Desc="描述">
                <AttrName>材料名称</AttrName>
                <AttrCode>材料编码</AttrCode>
            </Attr>
        </Attrs>
    </ServiceInfo>
</Services>

组装实体类

Services.java


import lombok.Data;

import javax.xml.bind.annotation.*;
import java.util.List;

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

    @XmlElement(name = "Total")
    Integer total;

    @XmlElement(name = "ServiceInfo", type = ServiceInfo.class)
    List<ServiceInfo> ServiceInfo;
}

ServiceInfo.java


import lombok.Data;

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

@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class ServiceInfo {

    @XmlElement(name = "Unid")
    String uuid;

    @XmlElement(name = "ServiceName")
    String serviceName;

    @XmlElement(name = "Infoprojid")
    String infoprojid;

    @XmlElement(name = "ServiceType")
    String serviceType;

    @XmlElement(name = "State")
    String state;

    @XmlElement(name = "PromiseDay")
    String promiseDay;

    @XmlElement(name = "UpdateTime")
    String updateTime;

    @XmlElement(name = "Attrs", type = Attrs.class)
    Attrs attrs;
}

Attrs.java


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Attrs {

    @XmlElement(name = "Attr", type = Attr.class)
    List<Attr> attrs;
}

Attr.java


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.xml.bind.annotation.*;

@NoArgsConstructor
@AllArgsConstructor
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Attr {

    @XmlAttribute(name = "Desc")
    String desc;

    @XmlElement(name = "AttrName")
    String attrName;

    @XmlElement(name = "AttrCode")
    String attrCode;
}

工具类


import javax.xml.bind.*;
import java.io.*;

/**
 * jaxb工具类
 */
public class JAXBUtil {

	/**
	 * XML转换为POJO类型
	 */
	@SuppressWarnings("rawtypes")
	public static Object unmarshall(String xml, Class clsToUnbound) throws JAXBException, UnsupportedEncodingException {
		JAXBContext jc = JAXBContext.newInstance(clsToUnbound);

		return unmarshall(jc, xml);
	}

	private static Object unmarshall(JAXBContext jc, String xml) throws JAXBException, UnsupportedEncodingException {
		Unmarshaller u = jc.createUnmarshaller();
		InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
		return u.unmarshal(is);
	}

	/**
	 * 从流中反序列化对象。
	 * 
	 * @param cls 需要反序列化的对象类型。
	 * @param xmlIs
	 *            流对象
	 * @return 经过反序列化的对象实例。
	 * @throws JAXBException
	 */
	public static Object unmarshall(InputStream xmlIs, Class<?> cls) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(cls);
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		Object obj = unmarshaller.unmarshal(xmlIs);
		return obj;
	}

	@SuppressWarnings("unchecked")
	public Object unmarshall(String xml, Class<? extends Object>... classes) throws JAXBException, IOException {
		InputStream is = new ByteArrayInputStream(xml.getBytes());
		JAXBContext jc = JAXBContext.newInstance(classes);
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		unmarshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
		Object obj = unmarshaller.unmarshal(is);
		return obj;
	}
	
	/**
	 * POJO类型转换为XML
	 * @param jc
	 * @param serObj
	 * @param formatOutput  是否格式化
	 * @param fragment 是否隐藏报文头
	 * @return
	 * @throws JAXBException
	 * @throws PropertyException
	 */
	private static String marshall(JAXBContext jc, Object serObj, boolean formatOutput, boolean fragment) throws JAXBException, PropertyException {
		StringWriter out = new StringWriter();
		Marshaller m = jc.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatOutput);
		m.setProperty(Marshaller.JAXB_FRAGMENT, fragment);
		m.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
		m.marshal(serObj, out);
		String tmp = out.toString();
		return tmp;
	}
	
	@SuppressWarnings("rawtypes")
	public static String marshall(Object serObj, Class clsToBound) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(clsToBound);
		return marshall(jc, serObj, true, false);
	}
	
	public static String marshall(Object serObj, boolean formatOutput, boolean fragment) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(serObj.getClass());
		return marshall(jc, serObj, formatOutput, fragment);
	}
	
	public static String marshall(Object serObj, boolean formatOutput) throws JAXBException {
		return marshall(serObj, formatOutput, false);
	}

	/**
	 * 将类序列化到流中。
	 * 
	 * @param contextPath 需要序列化到类名
	 * @param obj 需要序列化的实例对象
	 * @param stream 需要序列化到的流对象。
	 * @throws JAXBException
	 */
	public static void marshall(String contextPath, Object obj, OutputStream stream) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(contextPath);
		Marshaller m = jc.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		m.marshal(obj, stream);
	}

测试


public class JAXBUsage {
    public static void main(String[] args) {
        String xmlstr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "\n" +
                "<Services> \n" +
                "  <Total>1000</Total>  \n" +
                "  <ServiceInfo> \n" +
                "    <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>  \n" +
                "    <ServiceName><![CDATA[测试]]></ServiceName>  \n" +
                "    <ServiceType>1</ServiceType>  \n" +
                "    <State>I</State>  \n" +
                "    <PromiseDay>1</PromiseDay>  \n" +
                "    <UpdateTime>2019-01-11 08:38:46</UpdateTime>  \n" +
                "    <Attrs> \n" +
                "      <Attr> \n" +
                "        <AttrName><![CDATA[材料名称]]></AttrName>  \n" +
                "        <AttrCode>材料编码</AttrCode> \n" +
                "      </Attr> \n" +
                "    </Attrs> \n" +
                "  </ServiceInfo>  \n" +
                "  <ServiceInfo> \n" +
                "    <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>  \n" +
                "    <ServiceName><![CDATA[测试2]]></ServiceName>  \n" +
                "    <ServiceType>1</ServiceType>  \n" +
                "    <State>I</State>  \n" +
                "    <PromiseDay>1</PromiseDay>  \n" +
                "    <UpdateTime>2019-01-11 08:38:46</UpdateTime>  \n" +
                "    <Attrs> \n" +
                "      <Attr Desc = '描述'> \n" +
                "        <AttrName><![CDATA[材料名称]]></AttrName>  \n" +
                "        <AttrCode>材料编码</AttrCode> \n" +
                "      </Attr> \n" +
                "    </Attrs> \n" +
                "  </ServiceInfo> \n" +
                "</Services>\n";

        try{
            //xmlStr To pojo
            Services services = (Services)JAXBUtil.unmarshall(xmlstr, Services.class);
            System.out.println(services.toString());

            //pojo To xmlStr
            String s = JAXBUtil.marshall(services, Services.class);
            System.out.println(s);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

测试结果

Services(total=1000, ServiceInfo=[ServiceInfo(uuid=7B31FB4508BE82F2E6FB761E067E60CF, serviceName=测试, infoprojid=null, serviceType=1, state=I, promiseDay=1, updateTime=2019-01-11 08:38:46, attrs=Attrs(attrs=[Attr(desc=null, attrName=材料名称, attrCode=材料编码)])), ServiceInfo(uuid=7B31FB4508BE82F2E6FB761E067E60CF, serviceName=测试2, infoprojid=null, serviceType=1, state=I, promiseDay=1, updateTime=2019-01-11 08:38:46, attrs=Attrs(attrs=[Attr(desc=描述, attrName=材料名称, attrCode=材料编码)]))])
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Services>
    <Total>1000</Total>
    <ServiceInfo>
        <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>
        <ServiceName>测试</ServiceName>
        <ServiceType>1</ServiceType>
        <State>I</State>
        <PromiseDay>1</PromiseDay>
        <UpdateTime>2019-01-11 08:38:46</UpdateTime>
        <Attrs>
            <Attr>
                <AttrName>材料名称</AttrName>
                <AttrCode>材料编码</AttrCode>
            </Attr>
        </Attrs>
    </ServiceInfo>
    <ServiceInfo>
        <Unid>7B31FB4508BE82F2E6FB761E067E60CF</Unid>
        <ServiceName>测试2</ServiceName>
        <ServiceType>1</ServiceType>
        <State>I</State>
        <PromiseDay>1</PromiseDay>
        <UpdateTime>2019-01-11 08:38:46</UpdateTime>
        <Attrs>
            <Attr Desc="描述">
                <AttrName>材料名称</AttrName>
                <AttrCode>材料编码</AttrCode>
            </Attr>
        </Attrs>
    </ServiceInfo>
</Services>

注意

1、组装对象层级需遵循 xml 层级, 对象属性可以与 xml 不一致,但注解里的 name 属性需与xml 保持一致。

2、实体对象如果没有初始化值,转 xml 时会丢失该属性。如果属性不能丢失,那么则需要将其初始化,如果是集合则初始化为空集合。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值