我当前的代码完美地编码,并且我在生成的 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/