【问题标题】:JAX-RS Response for XML or JSON is not workingXML 或 JSON 的 JAX-RS 响应不起作用
【发布时间】:2016-07-17 10:03:03
【问题描述】:

我有以下 GenericRest 类,我用它来扩展基于用 @XmlRootElement 注释的实体类的 rest 类。

public class GenericRest<T extends BaseEntity> {

    @Inject @Service
    GenericService<T> service;

    public GenericService<T> getService() {
        return service;
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response getAll() {
        // This works for JSON but does not work for XML Requests.
        List<T> list = getService().findAll();
        // This just gives the attributes for the BaseEntity.
        //GenericEntity<List<T>> list = new GenericEntity<List<T>>(getService().findAll()) {};
        return Response.ok(list).build();
    }
}

APPLICATION_JSON 在当前未注释的情况下工作正常,但APPLICATION_XML 给出错误:

找不到响应对象类型的 MessageBodyWriter: 媒体类型的java.util.ArrayList:application/xml

注释的情况适用于两种 MediaType,但仅返回 BaseEntity 的属性,而不是扩展类的添加属性。如何获取扩展类的属性两种 MediaType 都可以工作?

完整的存储库可以在这里找到(正在进行中):https://github.com/martijnburger/multitenant

=== 更新 1 ===

我更改了实体上的@XmlSeeAlso 注释。它在特定实体上,但需要在 BaseEntity 上。此外,我使用了上面的GenericList 实现。这给出了正确的XML 响应。但是,它仍然只返回JSON 响应中的BaseEntity 属性。我有两个后续问题:

  1. 如何返回 JSON 响应,其中包括所请求的特定对象的属性?
  2. 如果在添加或删除特定的Entity 类时不必触摸BaseEntity,我会更喜欢它。因为@XmlSeeAlso注解每次新增Entity类,都需要更新注解。是否有另一种方法可以在我不需要触摸BaseEntity 的情况下实现这一点?

可以在此处找到包含更改的存储库:https://github.com/martijnburger/multitenant/tree/so_36291250

=== 更新 2 ===

我非常希望来自 Jackson 的 @JsonSubTypes 注释能够解决我的问题 1。但是,它没有。我使用 Jackson 注释更新了存储库,但在结果中看不到任何更改。

=== 更新 3 ===

请忽略我的更新 2。使用 Jackson 2 而不是 Jackson 1 时它完全有效。初学者错误。 :( 这给我留下了一个问题:每次添加实体时是否可以在不接触 BaseEntity 的情况下使其正常工作。

【问题讨论】:

  • The GenericEntity is needed。至于实体,您是否尝试将@XmlSeeAlso 放在BaseEntity 类上,指向子类,即@XmlSeeAlso({Car.class, Customer.class})
  • 啊!让我试试。我假设扩展类需要@XmlSeeAlse。但是,我希望每次添加实体时都不必触摸 BaseEntity。
  • 几乎很有趣。此更改适用于 XML 请求,但如果我尝试 JSON 请求,它仍然只返回 BaseEntity 属性。此处更新分支:github.com/martijnburger/multitenant/tree/so_36291250
  • 那么你是说在添加这个之前,JSON 产生了正确的结果?当您在评论中使用 "still" 一词时,我有点困惑,但在您的帖子中,您是说 JSON 产生正确的输出?
  • 它没有 GenericEntity 包装器。使用 GenericEntity 包装器,它只为 BaseEntity 生成属性。

标签: generics jax-rs java-ee-7


【解决方案1】:

您可以使用具有 XML 模块的 Jackson,而不是对 XML 使用 JAXB。对于 JAX-RS,您将使用 this artifact1

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-xml-provider</artifactId>
    <version>${jackson2.version}</version>

    <!-- you'll probably want to use the same version as
         the jackson being used on your wildfly -->

</dependency>

如果你使用它,XML 将由 Jackson 处理,它不像 JAXB 那样具有一些相同的怪癖。而且您所有的 Jackson JSON 注释也可以使用它,因此您只需要一组注释,用于 XML 和 JSON。在较低级别,Jackson XML 提供程序使用jackson-dataformat-xml,如果您想了解更多信息。

根据我的测试,只需将工件添加到您的项目中就足以使其工作,虽然我没有在 Wildfly 上进行测试,我只是用 RESTeasy 本身进行了测试。但我想应该仍然可以工作。

如果它不能解决问题,我唯一能想象的就是 JAXB 提供程序优先于这个提供程序。您可能需要在 jboss-structure.xml 文件中排除 resteasy-jaxb-provider。但就像我说的,我认为这不是必需的。我会用 Wildfly 进行测试,但我真的不想下载它:-)

额外

OP 正在使用类路径扫描2 来选择自动注册资源和提供者,但如果您在 Application 子类中手动注册资源和提供者,您还需要手动注册JacksonXMLProvider.class(或 JacksonJaxbXMLProvider.class,如果你想要 JAXB 注释支持)。


1 - 链接的项目显示为已弃用,但它链接到未弃用的更高版本。我链接到已弃用的那个,因为它在自述文件中有一些文档,尽管它很少。较新的项目根本没有文档。

2 - 用@ApplicationPath 注释的空Application 子类足以触发类路径扫描。一旦覆盖 getClasses()getSingletons() 并返回非空集,类路径扫描将被禁用。

【讨论】:

    【解决方案2】:

    所有变量在实体定义中必须是私有的。如果某人是公开的,则返回 json 响应但不返回 xml 响应。

    【讨论】:

      【解决方案3】:

      好的。最后,我为 XML 和 JSON 提出了一个单独的解决方案。在这个解决方案中,我不需要对 Generic 类进行任何注释(如 @XmlSeeAlso@JsonSubTypes)。此解决方案的唯一缺点是您无法在 Rest 类中为 XML 请求返​​回 Response 对象。

      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public Response getAllJSON() {
          return Response.ok(getService().findAll()).build();
      }
      
      @GET
      @Produces(MediaType.APPLICATION_XML)
      public List<T> getAllXML() {
          return getService().findAll();
      }
      

      如果有人知道更好的实现,我会删除这个答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-20
        • 2019-05-06
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 2013-12-15
        • 2011-03-14
        相关资源
        最近更新 更多