JAXB/Jackson技术咨询:无父标签的成对元素序列POJO构建
用JAXB解决与成对连续出现的XML-POJO映射需求
兄弟,我之前刚好踩过类似的XML序列化坑!你说的这种和成对连续出现的场景,用Jackson确实很难搞——毕竟它对集合默认就会加包装器,就算关掉包装,也没法直接把成对的属性拆成连续的独立标签。不过用JAXB的话,通过适配器就能完美解决,给你详细说下步骤:
1. 先明确目标XML结构
假设你需要处理的XML是这种严格成对的格式:
valueA1 valueB1 valueA2 valueB2
2. 创建成对元素的POJO
先定义一个ABPair类,用来封装一组和的值:
import javax.xml.bind.annotation.XmlElement; public class ABPair { private String a; private String b; @XmlElement(name = "A") public String getA() { return a; } public void setA(String a) { this.a = a; } @XmlElement(name = "B") public String getB() { return b; } public void setB(String b) { this.b = b; } }
3. 编写JAXB适配器处理交替元素
核心是用XmlAdapter把List<ABPair>和交替的/元素做转换。先写一个临时的中间类,用来映射XML里的所有和列表:
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; import java.util.List; // 临时类,用于JAXB适配器的中转映射 @XmlRootElement(name = "root") class TempRoot { private List<String> aList = new ArrayList<>(); private List<String> bList = new ArrayList<>(); @XmlElement(name = "A") public List<String> getaList() { return aList; } public void setaList(List<String> aList) { this.aList = aList; } @XmlElement(name = "B") public List<String> getbList() { return bList; } public void setbList(List<String> bList) { this.bList = bList; } }
然后写适配器类,负责在List<ABPair>和TempRoot之间互相转换:
import javax.xml.bind.annotation.adapters.XmlAdapter; import java.util.ArrayList; import java.util.List; public class ABPairAdapter extends XmlAdapter<TempRoot, List<ABPair>> { // 把XML解析成List<ABPair> @Override public List<ABPair> unmarshal(TempRoot tempRoot) throws Exception { List<ABPair> pairs = new ArrayList<>(); List<String> aList = tempRoot.getaList(); List<String> bList = tempRoot.getbList(); // 假设XML里的A和B是严格成对的,数量一致 for (int i = 0; i < aList.size(); i++) { ABPair pair = new ABPair(); pair.setA(aList.get(i)); pair.setB(bList.get(i)); pairs.add(pair); } return pairs; } // 把List<ABPair>序列化成XML的交替A/B元素 @Override public TempRoot marshal(List<ABPair> abPairs) throws Exception { TempRoot tempRoot = new TempRoot(); List<String> aList = new ArrayList<>(); List<String> bList = new ArrayList<>(); for (ABPair pair : abPairs) { aList.add(pair.getA()); bList.add(pair.getB()); } tempRoot.setaList(aList); tempRoot.setbList(bList); return tempRoot; } }
4. 创建根节点POJO并关联适配器
最后定义根节点类,用@XmlJavaTypeAdapter指定适配器:
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import java.util.List; @XmlRootElement(name = "root") public class Root { private List<ABPair> abPairs; @XmlJavaTypeAdapter(ABPairAdapter.class) public List<ABPair> getAbPairs() { return abPairs; } public void setAbPairs(List<ABPair> abPairs) { this.abPairs = abPairs; } }
5. 测试序列化/反序列化
写个简单的测试代码验证效果:
import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) throws Exception { // 构造测试数据 Root root = new Root(); List<ABPair> pairs = new ArrayList<>(); ABPair pair1 = new ABPair(); pair1.setA("valueA1"); pair1.setB("valueB1"); pairs.add(pair1); ABPair pair2 = new ABPair(); pair2.setA("valueA2"); pair2.setB("valueB2"); pairs.add(pair2); root.setAbPairs(pairs); // 序列化成XML并输出 JAXBContext context = JAXBContext.newInstance(Root.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(root, System.out); } }
运行后就能得到你要的和成对连续的XML结构啦!
再补充下为什么Jackson不适合这个场景:Jackson的XML模块默认会给集合加包装标签,就算用@JacksonXmlElementWrapper(useWrapping = false)关掉包装,它也会把每个ABPair实例序列化成<ABPair>包裹的内容,而不是直接拆成独立的<A>和<B>标签,很难实现你要的无包装成对序列效果。所以JAXB的适配器方案是更合适的选择。
内容的提问来源于stack exchange,提问作者narendra-choudhary
相关产品推荐
相关产品推荐

