JAXB / Jersey问题,带有接口的解组复杂类型

时间:2012-06-29 01:38:00

标签: java jaxb jersey

我正在努力解决JSon的少数问题,并且看起来我永远不会让它发挥作用:(

查看第一个问题:我有一个包含几个字段的类Response:String error,String error_code和Object response。负责将所有数据填入响应的类,如果需要填写错误字段并将其发送回客户端以进行进一步的分析。

"对象响应"可以是任何类型(为什么对象?因为它没有使用接口,这将是问题的第二部分)

代码段

   @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Response
    {
        public static final String ERROR_FIELD_NAME = "error";
        public static final String ERROR_CODE_FIELD_NAME = "error_code";
        public static final String RESPONSE_FIELD_NAME = "response";

        @XmlElement(name = Response.ERROR_CODE_FIELD_NAME)
        private String errorCode;

        @XmlElement(name = Response.ERROR_FIELD_NAME)
        private String errorMessage;

        @XmlElementRefs(
            {@XmlElementRef(type = AClassResponse.class),
        @XmlElementRef(type = BClassResponse.class)})
        private Object entity;

等...

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;


//@XmlRootElement(name = Response.RESPONSE_FIELD_NAME)
//@XmlJavaTypeAdapter(AClassResponse.Adapter.class)
@XmlRootElement
public class AClassResponse
{
    private TargetObject target;


    public TargetObject getTarget()
    {
        return target;
    }


    public void setTarget(TargetObject target)
    {
        this.target = target;
    }
}

JSON 1 (for XmlElementRef AClassResponse.class ):
    { 
      "error" : "",
      "error_code" : "",
      **"aClassResponse" :** 
         { "target" : 
            { "accountId" : "5bd0812b",
              "id" : "6ccb6ae1-30c3-4aa0-8d1e-6ed61b6bb217",
              "isCaseSensitive" : "false",
              "maxNumberOfConnections" : "0",
              "name" : "targetName",
              "pathDelimiter" : "/",
              "type" : "SMB"
            } 
         }
    }

JSON 1 (for XmlElementRef BClassResponse.class):
   { 
      "error" : "",
      "error_code" : "",
      **"bClassResponse" :** 
         { "target" : 
            { "accountId" : "5bd0812b",
              "id" : "6ccb6ae1-30c3-4aa0-8d1e-6ed61b6bb217",
              "isCaseSensitive" : "false",
              "maxNumberOfConnections" : "0",
              "name" : "targetName",
              "pathDelimiter" : "/",
              "type" : "SMB"
            } 
         }
    }

现在出现问题:

查看上面的JSon," aClassResponse" :" bClassResponse" :总是动态的(意思是名称来自类名) - 这不是我需要的。

我的目标是为此名称提供持久性名称"响应" ,以便任何远程客户端都能够了解此名称并依赖此名称。

我知道,为了解决这个问题,我可以使用 @XmlRootElement(名称="响应")注释 AClassResponse.class ,它确实可以正常工作你定义了多个@XmlElementRef。

如果两个或更多,这会导致封送/解组的问题,并且JAXB不知道要绑定的类应该绑定到实体字段,因为它也依赖于名称(name =&#34 ;响应&#34)

@XmlElementRefs(
        {@XmlElementRef(type = AClassResponse.class),
        @XmlElementRef(type = BClassResponse.class)})
        private Object entity;

它像这样对待:

@XmlElementRefs(
            {@XmlElementRef(name = "response", type = AClassResponse.class),
            @XmlElementRef(name = "response", type = BClassResponse.class)})
            private Object entity;

假设这是一个正确的行为,我无法为任何对象类型保持相同(name =" response")。

好的,我尝试通过为每个实现引入接口而不是Object类型+ @XmlJavaTypeAdapter(AClassResponse.Adapter.class)来解决它 - 但是它也没有工作,抛出异常,不支持接口和等...

这篇文章似乎可以阐明这一点,http://jaxb.java.net/guide/Mapping_interfaces.html

但它也失败了,说它不能实例化抽象类抽象类AbstractFooImpl

@XmlJavaTypeAdapter(AbstractFooImpl.Adapter.class)
interface IFoo {
  ...
}
**abstract class AbstractFooImpl implements IFoo {**
  ...

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

class SomeFooImpl extends AbstractFooImpl {
  @XmlAttribute String name;
  ...
}

class AnotherFooImpl extends AbstractFooImpl {
  @XmlAttribute int id;
  ...
}

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

有关我如何解决此问题的任何建议?请帮忙..

谢谢。

2 个答案:

答案 0 :(得分:0)

您可以使用@XmlElements注释并执行以下操作:

@XmlElements({
    @XmlElementRef(name = "response", type = AClassResponse.class),
    @XmlElementRef(name = "response", type = BClassResponse.class)
})
private Object entity;

答案 1 :(得分:0)

JAXB不做接口。解决方案是泛型或抽象类(使用@XmlTransient注释以使JAXB忽略基类,而@XmlSeeAlso使其使用特定实现)。这解决了Java部分,但你仍然需要修复等式的XSD部分(请记住,JAXB只能通过Jersey看到你的JSON的XML版本)。

为此,您可以在字段上使用@XmlElementRef和@XmlElementRefs注释,以便XSD将映射到特定实现的选择。

@XmlTransient // JAXB doesn't like abstract types, so do not map this type name
// XmlSeeAlso only required if BaseImpl/BaseImpl2 are not otherwise auto-discovered by JAXB
@XmlSeeAlso({BaseImpl.class, BaseImpl2.class })
public abstract class Base {
  @XmlElement(name='still-works')
  public String thisFieldWillStillBeMappedByJAXB;
}

@XmlRootElement("base-impl")
public class BaseImpl {}

@XmlRootElement("alternative")
public class BaseImpl2 {}

public class Complex<E extends Base> {
   @XmlElementRefs({
     @XmlElementRef(type=BaseImpl.class), 
     @XmlElementRef(type=BaseImpl2.class)
   })
   public E impl; // will be an instance of either "base-impl" or "alternative"
}