【问题标题】:JAXB Can't handle interfacesJAXB 无法处理接口
【发布时间】:2010-11-04 21:46:25
【问题描述】:

我认为这个问题已经被问了一百万次了,但没有一个建议的解决方案对我有用。这是我的示例实现

public class FooImpl2 implements Foo {
    private int a = 100 ;
    private String b = "I am FooImpl2";
    private boolean c;

    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
    public String getB() {
        return b;
    }
    public void setB(String b) {
        this.b = b;
    }
    public boolean isC() {
        return c;
    }
    public void setC(boolean c) {
        this.c = c;
    }

}

@XmlRootElement
@XmlSeeAlso({FooImpl1.class, FooImpl2.class})
public interface Foo {}

public class FooImpl1 implements Foo {    
    private int x;
    private String y ="I am FooImpl1";
    private boolean z;

    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public String getY() {
        return y;
    }
    public void setY(String y) {
        this.y = y;
    }
    public boolean isZ() {
        return z;
    }
    public void setZ(boolean z) {
        this.z = z;
    }        
}

@XmlRootElement
public class Response{

    private Foo foo;

    @XmlElement(type=Object.class)
    public Foo getFoo() {
        return foo;
    }

    public void setFoo(Foo foo) {
        this.foo = foo;
    }

}

public class SimpleResource {    
    @Path("foo/{val}") @Produces({"application/json"}) @GET
    public FooAdapter getFoo(@QueryParam("val") int val) {
        FooAdapter ret = new FooAdapter();
        if(val % 2 == 0) {
            ret.setFoo(new FooImpl2());
        } else {
            ret.setFoo(new FooImpl1());
        }

        return ret;
    }

我总是遇到以下异常

com.sun.xml.bind.v2.runtime.IllegalAnnotationsException:2 个计数 IllegalAnnotationExceptions com.abc.objectsToReturn.Foo 是一个 界面,

谁能帮我找出正确的解决方案

【问题讨论】:

  • 如果是抽象类也会失败吗?
  • @Woot4Moo 的建议与我在 JAXB 中发现的一致:interface = doesn't work, abstract class= works

标签: java jaxb


【解决方案1】:

这并不是真正的接口问题,您只需要更改引导 JAXBContext 的方式。

如果你改成下面这样:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Response.class, FooImpl1.class, FooImpl2.class);

        Response response = new Response();
        FooImpl1 foo = new FooImpl1();
        response.setFoo(foo);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(response, System.out);
    }
}

然后您将获得以下输出(使用任何 JAXB 实现:MetroMOXy 等):

<response>
   <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="fooImpl1">
      <x>0</x>
      <y>I am FooImpl1</y>
      <z>false</z>
   </foo>
</response>

MOXy JAXB 让您的整个模型成为接口,结帐:

我还有一篇博文可能与您尝试构建的内容相关:

【讨论】:

  • Blaise 感谢这个例子,但这并没有解决我的问题:(
  • 你遇到了什么问题?您需要在类路径中包含 eclipselink.jar,添加适当的 jaxb.properties,并实现 ObjectFactory 以返回 impl 类的实例。
  • 我在示例代码中没有看到对来自 eclipselink.jar 的类的任何引用。另外,ObjectFactory 是如何知道它必须获取 jaxb.properties 的?
  • JAXB 是具有标准运行时的规范。 jaxb.properties 用于指定应使用的 JAXB 运行时。如果没有 jaxb.properties 文件,则使用 JRE 中的默认 JAXB 版本。 JAXB 运行时使用 ObjectFactory 来实例化类的实例。
  • 我已经修改了我的答案。更改引导 JAXBContext 的方式将消除接口问题,并且可以跨任何 JAXB 实现移植。
【解决方案2】:

当您使用接口只是为了隐藏您的实现类以防止暴露,并且当类和接口之间存在一对一(或接近一对一)关系时,可以使用 XmlJavaTypeAdapter,如下所示。

@XmlJavaTypeAdapter(FooImpl.Adapter.class)
interface IFoo {
  ...
}
class FooImpl implements IFoo {
  @XmlAttribute
  private String name;
  @XmlElement
  private int x;

  ...

  static class Adapter extends XmlAdapter<FooImpl,IFoo> {
    IFoo unmarshal(FooImpl v) { return v; }
    FooImpl marshal(IFoo v) { return (FooImpl)v; }
  }
}

class Somewhere {
  public IFoo lhs;
  public IFoo rhs;
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-27
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 2018-07-18
相关资源
最近更新 更多