You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于method的name属性解组相似包装的XML到POJO?

可行实现方案

方案一:使用XmlAdapter自定义转换逻辑

XmlAdapter可以让你手动控制XML节点到POJO的转换流程,刚好适配根据method的name属性选择对应子类的场景。

1. 编写适配器类

创建继承自XmlAdapter<MethodAdapter.AdaptedMethod, VeraWSMethod>的适配器,在unmarshal方法里根据name属性判断实例化的子类:

public class MethodAdapter extends XmlAdapter<MethodAdapter.AdaptedMethod, VeraWSMethod> {

    // 适配类,映射XML中的method节点
    @XmlRootElement(name = "method")
    public static class AdaptedMethod {
        @XmlAttribute
        public String name;
        
        @XmlAnyElement(lax = true)
        public List<Object> content;
    }

    @Override
    public VeraWSMethod unmarshal(AdaptedMethod adaptedMethod) throws Exception {
        VeraWSMethod method;
        // 根据method的name属性选择对应子类
        switch (adaptedMethod.name) {
            case "place-info":
                method = new MethodXX1();
                break;
            case "another-method":
                method = new MethodXX2();
                break;
            default:
                throw new IllegalArgumentException("未知method名称: " + adaptedMethod.name);
        }
        // 将适配类的内容解组到目标对象
        JAXBContext ctx = JAXBContext.newInstance(method.getClass());
        Unmarshaller unmarshaller = ctx.createUnmarshaller();
        for (Object node : adaptedMethod.content) {
            if (node instanceof Element) {
                unmarshaller.unmarshal((Element) node, method.getClass());
            }
        }
        method.setName(adaptedMethod.name);
        return method;
    }

    @Override
    public AdaptedMethod marshal(VeraWSMethod method) throws Exception {
        // 如需编组XML,实现反向转换逻辑
        AdaptedMethod adapted = new AdaptedMethod();
        adapted.name = method.getName();
        JAXBContext ctx = JAXBContext.newInstance(method.getClass());
        Marshaller marshaller = ctx.createMarshaller();
        DOMResult result = new DOMResult();
        marshaller.marshal(method, result);
        Node root = result.getNode();
        if (root instanceof Document) {
            adapted.content = Collections.singletonList(((Document) root).getDocumentElement());
        }
        return adapted;
    }
}

2. 在VeraWSClass中引用适配器

给method字段的getter添加@XmlJavaTypeAdapter注解:

@XmlRootElement(name = "class")
public class VeraWSClass {
    // 原有属性的getter/setter保持不变

    @XmlJavaTypeAdapter(MethodAdapter.class)
    public VeraWSMethod getMethod() {
        return method;
    }

    public void setMethod(VeraWSMethod method) {
        this.method = method;
    }
}

方案二:自定义Unmarshaller.Listener监听解组过程

通过监听解组完成事件,在afterUnmarshal方法里根据method的属性替换实例:

@XmlRootElement(name = "class")
public class VeraWSClass {
    private String name;
    private String version;
    private String revision;
    // 临时接收method节点的适配类
    private TempMethod tempMethod;
    // 最终的method对象
    private VeraWSMethod method;

    // 原有属性的getter/setter不变

    @XmlElement(name = "method")
    public TempMethod getTempMethod() {
        return tempMethod;
    }

    public void setTempMethod(TempMethod tempMethod) {
        this.tempMethod = tempMethod;
    }

    // 解组完成后自动触发的方法
    private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) throws JAXBException {
        if (tempMethod == null) return;
        JAXBContext ctx = JAXBContext.newInstance(MethodXX1.class, MethodXX2.class);
        Unmarshaller methodUnmarshaller = ctx.createUnmarshaller();
        // 根据name属性转换为对应子类
        switch (tempMethod.name) {
            case "place-info":
                method = methodUnmarshaller.unmarshal(tempMethod.getSource(), MethodXX1.class).getValue();
                break;
            case "another-method":
                method = methodUnmarshaller.unmarshal(tempMethod.getSource(), MethodXX2.class).getValue();
                break;
            default:
                throw new IllegalArgumentException("未知method: " + tempMethod.name);
        }
        tempMethod = null;
    }

    // 临时类,捕获method的原始XML结构
    @XmlRootElement(name = "method")
    public static class TempMethod {
        @XmlAttribute
        public String name;

        @XmlAnyElement
        private List<Element> elements;

        public Source getSource() {
            Document doc = elements.get(0).getOwnerDocument();
            Element methodElement = doc.createElement("method");
            methodElement.setAttribute("name", name);
            for (Element elem : elements) {
                methodElement.appendChild(doc.importNode(elem, true));
            }
            return new DOMSource(methodElement);
        }
    }

    // 对外暴露实际的method对象(无需XML注解)
    public VeraWSMethod getMethod() {
        return method;
    }

    public void setMethod(VeraWSMethod method) {
        this.method = method;
    }
}

方案三:结合@XmlSeeAlso与动态类型判断

如果子类都已配置JAXB注解,可以用@XmlSeeAlso声明所有子类,解组后再根据name属性强转类型:

1. 在父类添加@XmlSeeAlso

@XmlSeeAlso({MethodXX1.class, MethodXX2.class})
public abstract class VeraWSMethod {
    @XmlAttribute
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2. 修改VeraWSClass的method字段

直接用@XmlElement映射,解组后手动判断类型:

@XmlRootElement(name = "class")
public class VeraWSClass {
    // 原有属性不变

    @XmlElement(name = "method")
    public VeraWSMethod getMethod() {
        return method;
    }

    public void setMethod(VeraWSMethod method) {
        this.method = method;
    }

    // 新增获取具体类型的方法
    public <T extends VeraWSMethod> T getConcreteMethod(Class<T> clazz) {
        if (clazz.isInstance(method)) {
            return clazz.cast(method);
        }
        throw new ClassCastException("method类型不匹配: " + clazz.getName());
    }
}

使用示例

解组完成后根据name属性处理对应子类:

VeraWSClass wsClass = unmarshaller.unmarshal(xmlSource, VeraWSClass.class).getValue();
VeraWSMethod method = wsClass.getMethod();
if ("place-info".equals(method.getName())) {
    MethodXX1 placeInfo = (MethodXX1) method;
    // 处理place-info的业务逻辑
} else if ("another-method".equals(method.getName())) {
    MethodXX2 anotherMethod = (MethodXX2) method;
    // 处理another-method的业务逻辑
}

内容的提问来源于stack exchange,提问作者František Slabý

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:39:53