XML 或 JSON 的 JAX-RS 响应不工作
JAX-RS Response for XML or JSON is not working
我有以下 GenericRest class,我用它来扩展 rest classes,它基于用 @XmlRootElement 注释的实体 classes。
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
给出错误:
Could not find MessageBodyWriter for response object of type:
java.util.ArrayList of media type: application/xml
评论的情况适用于两种 MediaType,但 return 只是 BaseEntity
的属性,而不是扩展 classes 的添加属性。如何获得扩展 classes 和 的属性,让两个 MediaTypes 都能正常工作?
可以在此处找到完整的存储库(进行中):https://github.com/martijnburger/multitenant
=== 更新 1 ===
我更改了实体上的 @XmlSeeAlso
注释。它在特定实体上,但需要在 BaseEntity
上。此外,我使用了上面的 GenericList
实现。这给出了正确的 XML
响应。但是,它仍然 return 仅 JSON
回复中的 BaseEntity
属性。我有两个后续问题:
- 如何return
JSON
响应包括所请求的特定对象的属性?
- 如果在添加或删除特定的
Entity
class 时不必触及 BaseEntity
,我会更喜欢它。因为@XmlSeeAlso
注解每次新增Entity
class,都需要更新注解。有没有另一种方法可以实现这个我不需要触摸 BaseEntity
?
可以在此处找到有更改的存储库:https://github.com/martijnburger/multitenant/tree/so_36291250
=== 更新 2 ===
我很希望 Jackson 的 @JsonSubTypes
注释能解决我的问题 1。然而,它没有。我用 Jackson 注释更新了存储库,但我看不到结果有任何变化。
=== 更新 3 ===
请忽略我的更新 2。当使用 Jackson 2 而不是 Jackson 1 时它完全有效。初学者错误。 :(
这给我留下了一个问题:是否可以在每次添加实体时不触及 BaseEntity 的情况下使它正常工作。
好的。最后,我为 XML 和 JSON 想出了一个单独的解决方案。在此解决方案中,我不需要对通用 classes(如 @XmlSeeAlso
和 @JsonSubTypes
)进行任何注释。此解决方案的唯一缺点是您不能 return 在 Rest class 中的 Response
对象用于 XML 请求。
@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();
}
如果有人知道更好的实现,我会删除这个答案。
您可以使用 Jackson,而不是将 JAXB 用于 XML,它有一个 XML 模块。对于 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 - 链接的项目显示为已弃用,但它链接到未弃用的更高版本。我链接到已弃用的那个,因为它在 README 中有一些文档,尽管它很少。较新的项目根本没有文档。
2 - 用 @ApplicationPath
注释的空 Application
子类足以触发类路径扫描。一旦覆盖 getClasses()
或 getSingletons()
和 return 非空集,类路径扫描将被禁用。
实体定义中的所有变量都必须是私有的。如果某人 public 做出 return json 响应但没有 return xml 响应。
我有以下 GenericRest class,我用它来扩展 rest classes,它基于用 @XmlRootElement 注释的实体 classes。
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
给出错误:
Could not find MessageBodyWriter for response object of type: java.util.ArrayList of media type: application/xml
评论的情况适用于两种 MediaType,但 return 只是 BaseEntity
的属性,而不是扩展 classes 的添加属性。如何获得扩展 classes 和 的属性,让两个 MediaTypes 都能正常工作?
可以在此处找到完整的存储库(进行中):https://github.com/martijnburger/multitenant
=== 更新 1 ===
我更改了实体上的 @XmlSeeAlso
注释。它在特定实体上,但需要在 BaseEntity
上。此外,我使用了上面的 GenericList
实现。这给出了正确的 XML
响应。但是,它仍然 return 仅 JSON
回复中的 BaseEntity
属性。我有两个后续问题:
- 如何return
JSON
响应包括所请求的特定对象的属性? - 如果在添加或删除特定的
Entity
class 时不必触及BaseEntity
,我会更喜欢它。因为@XmlSeeAlso
注解每次新增Entity
class,都需要更新注解。有没有另一种方法可以实现这个我不需要触摸BaseEntity
?
可以在此处找到有更改的存储库:https://github.com/martijnburger/multitenant/tree/so_36291250
=== 更新 2 ===
我很希望 Jackson 的 @JsonSubTypes
注释能解决我的问题 1。然而,它没有。我用 Jackson 注释更新了存储库,但我看不到结果有任何变化。
=== 更新 3 ===
请忽略我的更新 2。当使用 Jackson 2 而不是 Jackson 1 时它完全有效。初学者错误。 :( 这给我留下了一个问题:是否可以在每次添加实体时不触及 BaseEntity 的情况下使它正常工作。
好的。最后,我为 XML 和 JSON 想出了一个单独的解决方案。在此解决方案中,我不需要对通用 classes(如 @XmlSeeAlso
和 @JsonSubTypes
)进行任何注释。此解决方案的唯一缺点是您不能 return 在 Rest class 中的 Response
对象用于 XML 请求。
@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();
}
如果有人知道更好的实现,我会删除这个答案。
您可以使用 Jackson,而不是将 JAXB 用于 XML,它有一个 XML 模块。对于 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 - 链接的项目显示为已弃用,但它链接到未弃用的更高版本。我链接到已弃用的那个,因为它在 README 中有一些文档,尽管它很少。较新的项目根本没有文档。
2 - 用 @ApplicationPath
注释的空 Application
子类足以触发类路径扫描。一旦覆盖 getClasses()
或 getSingletons()
和 return 非空集,类路径扫描将被禁用。
实体定义中的所有变量都必须是私有的。如果某人 public 做出 return json 响应但没有 return xml 响应。