java - Jaxb 是否可以解码到接口(interface)?

标签 java interface jaxb marshalling unmarshalling

我当前的代码完美地编码,并且我在生成的 XML 中得到了我想要的元素。即<food>Beef</food>

但是,当我必须将其解码回 java 对象时,问题就出现了。除了食物变量之外,一切都返回正常。我本来没有XmlElement(required = true)在顶部,并且食物元素总是会解码回空。然后,我添加了 required=true 部分,但我遇到了界面问题。我做了一些挖掘,据我所知,jaxb 无法真正解码到接口(interface)中,因为它不知道要编码的具体类型。

当前错误(如果有帮助):

Can not set FoodInterface field BigPayload.food to 
com.sun.org.apache.xerces.internal.dom.ElementNSImpl

我的Java类如下:

@XmlSeeAlso({MeatFoods.class, VeggieFoods.class})
@XmlType(name ="BigPayload", propOrder = //stuff goes here
@XmlRootElement(name = foodPayload)
public class BigPayload implements Payload{
    @XmlElements({@XmlElement(type = MeatFoods.class), 
                  @XmlElement(type = VeggieFoods.class),
                  @XmlElement(required = true)})
    protected FoodInterface food;
    protected Grade grade;
    //grade/food setters and getters
}
@XmlTransient //If this isn't here, I get the jaxB cannot handle interfaces and no default constructor error
public interface FoodInterface{ //stuff here}
@XmlType(name = "MeatFoods")
@XmlEnum
public enum MeatFoods implements FoodInterface{
    Chicken(1, Chicken)
    Beef(2, Beef)
    Pork(3, Pork)

    int value;
    String name;

    @Override
    public int getValue()

    @Override
    public String getName()

    public static FoodInterface getEnumFromValue(int value){//gets stuff}
    public static FoodInterface getEnumFromName(String name){//gets stuff}
}

我只是想知道这是否正确,并且没有真正好的方法来解码接口(interface)类型。这是真的?我看到很多其他问题都是关于编码接口(interface)的,而解码问题并没有真正得到令我满意的答案。任何答案都值得赞赏,我知道这不是一个最小的可重现示例,但我更多的是寻找口头答案,而不是代码修复或任何东西。不过,如果代码中有任何明显错误,请告诉我!

最佳答案

对于标准情况,JAXB 只能使用(抽象)类而不是接口(interface)。

我能想到的选项

  • 您可以使用带有@XmlAdapter的接口(interface)。参见示例:[1]
  • 使用Object进行JAXB绑定(bind)并通过强制转换公开接口(interface)。 (也许将验证逻辑添加到`afterUnmarshal(Unmarshaller u,Objectparent)中。[2]
  • 将私有(private)字段绑定(bind)到@XmlAnyElement,并在afterUnmarshal(Unmarshaller, Object)中进行一些进一步处理,将@XmlTransient添加到目标。参见示例:[3]

只要有一些创造力,可能还有其他选择。但我认为所有这些基本上都归结为:尝试获取“原始”解析选项并手动填充接口(interface)引用。

[1]

public static interface Food {
    String name();
}
public enum Veggie implements Food {
    SALAD;
}
public static enum Meat implements Food {
    CHICKEN;
}

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public static class UseInterface {

    @XmlJavaTypeAdapter(FoodAdapter.class)
    @XmlAttribute
    private Food food;

    public Food getFood() {
        return food;
    }

    public void setFood(Food food) {
        this.food = food;
    }
}

public static class FoodAdapter extends XmlAdapter<String, Food> {

    @Override
    public Food unmarshal(String v) throws Exception {
        try {
            return Veggie.valueOf(v);
        } catch (IllegalArgumentException e) {

        }
        try {
            return Meat.valueOf(v);
        } catch (IllegalArgumentException e) {

        }
        throw new IllegalArgumentException("Unknown Food:" + v);
    }

    @Override
    public String marshal(Food v) throws Exception {
        return v.name();
    }

}

[2]

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public static class UseInterface {

    @XmlElement
    private Object food;

    public Food getFood() {
        return (Food) food;
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        if (food != null && !(food instanceof Food)) {
            throw new IllegalArgumentException("food is of wrong type: " + food.getClass().getName());
        }
    }
}

JAXBContext newInstance = JAXBContext.newInstance(UseInterface.class, Meat.class, Veggie.class);
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><useInterface><food xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"meat\">CHICKEN</food></useInterface>";

newInstance.createUnmarshaller().unmarshal(new StringReader(xml));

[3]

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public static class UseInterface {

    @XmlAnyElement
    private org.w3c.dom.Element foo;

    @XmlTransient
    private SomeInterface ifc


    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        NamedNodeMap attributes = foo.getAttributes();
        // do something with foo on DOM level to bind the subtree to an interface manually
    }
}

关于java - Jaxb 是否可以解码到接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58142368/

相关文章:

java - 不使用扩展在 DispatcherServlet 中找不到映射

java - Intellij思想: from sources to project using Maven

java - 处理类之间的对象

java - 循环 jaxb marshall

java - 使用 startActivityForResult() 获取结果

java - 一个很好的网络数学 Java 库

c# - 无法在 C# 中将子接口(interface)作为参数传递

国际象棋接口(interface)基类的 C++ 数组

java - 由 Weblogic 11g 中的 : java. lang.ClassNotFoundException: org/apache/xerces/jaxp/DocumentBuilderFactoryImpl 引起

java - 3 项 IllegalAnnotationExceptions