Java Jackson和JAX-RS:基于@PathParam的类型解析抽象类型
假设Java Jackson和JAX-RS:基于@PathParam的类型解析抽象类型,java,jackson,jax-rs,Java,Jackson,Jax Rs,假设Animal在我的项目中是一个抽象类,我有一个REST资源(在JAX-RS服务器上,使用Jackson进行(反)序列化),用于PUT操作存储在数据库中的动物。它们有具体的类型,REST资源在请求路径中指定类型: @PUT @Consumes(MediaType.APPLICATION_JSON) @Path("/{entityType}/{id: \\d+}") public <T extends Animal> void putAnimal(@PathParam("entity
Animal
在我的项目中是一个抽象类,我有一个REST资源(在JAX-RS服务器上,使用Jackson进行(反)序列化),用于PUT
操作存储在数据库中的动物。它们有具体的类型,REST资源在请求路径中指定类型:
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{entityType}/{id: \\d+}")
public <T extends Animal> void putAnimal(@PathParam("entityType") String entityType, @PathParam("id") String id, Animal input) throws IOException {
//...
}
@PUT
@使用(MediaType.APPLICATION_JSON)
@路径(“/{entityType}/{id:\\d+}”)
public void putAnimal(@PathParam(“entityType”)字符串entityType,@PathParam(“id”)字符串id,动物输入)引发IOException{
//...
}
我想使用entityType
来选择具体的类来进行反序列化(Dog
或Cat
或任何东西,因为entityType
是Dog
或Cat
或任何东西)。由于此处难以解释的原因,我无法将类型信息放入JSON输入本身
因此,用自定义的TypeIdResolver
或类似的东西来注释Animal
对我没有帮助,因为类型信息不在JSON本身中(这就是类型解析程序将获得的所有信息)。我本来打算使用一个自定义的MessageBodyReader
,但据我所知,它无法从其readValue
方法中传递的body中获取其他参数值,因此我不知道反序列化成什么
我错过了什么?如果这种方法失败了,我如何在不指定特定于动物的端点的情况下实现我想要的目标(这会导致大量重复的代码以及通用性的丧失-现在我可以添加
animal
的一个子类,而此代码将正常工作,这非常好。)以下引用自JAX-RS规范(5.2.2 URI和URI模板)建议您应该能够将UriInfo
实例注入自定义MessageBodyReader
,并使用其方法之一检查请求的URL路径
可以使用@Context An-notation将UriInfo的实例注入类字段或方法参数中。UriInfo提供了关于请求URI组件的静态和动态信息
这里提供的示例显示了一个接收UriInfo
参数的资源方法,但通常也可以将实例注入提供者(MessageBodyReader
)
在通过
UriInfo
获得entityType
路径参数后,您的MessageBodyReader
应该能够提供Animal
的相应子类。鉴于您正试图做的事情,您最好构建一个AnimalResource
类,其中包含您的基本方法和构建独立的DogResource
、CatResource
以及扩展AnimalResource
所需的任何其他类。这将允许您获得Animal
的正确子类,从而正确反序列化输入JSON
更新
这是如何实现的示例。您的基本资源如下所示:
public class AnimalResource<T extends Animal>
{
private final transient AnimalService<T> service;
public AnimalResource(final AnimalService<T> service)
{
this.service = service;
}
@Get
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public T getbyId(@PathParam("id") final String id)
{
return this.service.findById(id);
}
// Other CRUD methods go here
}
公共类动物资源
{
私人临时动物服务;
公共动物资源(最终动物服务)
{
服务=服务;
}
@得到
@路径(“{id}”)
@产生(MediaType.APPLICATION_JSON)
公共T getbyId(@PathParam(“id”)最终字符串id)
{
返回此.service.findById(id);
}
//其他积垢方法也在这里
}
然后你的个体动物,假设它们都有相同的设置,简单地说:
@Path("/cats")
public class CatResource extends AnimalResource<Cat>
{
public CatResource(final CatService catService)
{
super(catService);
}
}
@Path(“/cats”)
公共类CatResource扩展了AnimalResource
{
公共CatResource(最终CatService CatService)
{
超级(有线电视服务);
}
}
为了一只猫和一只猫
@Path("/dogs")
public class DogResource extends AnimalResource<Dog>
{
public DogResource(final DogService dogService)
{
super(dogService);
}
}
@Path(“/dogs”)
公共类DogResource扩展了AnimalResource
{
公共狗资源(最终狗服务狗服务)
{
超级(狗服务);
}
}
对于狗来说。它们将从父母那里继承标准的CRUD方法,任何特定于动物的方法仍然可以放在单个
*资源类中。正如我在问题中已经说过的,这将导致重复代码和失去通用性。您也没有说明为什么我这样做比我目前的方法更好。这是这在项目中也不实用,因为我们基本上会在运行时添加动物。在运行时添加JAX-RS资源并不有趣。首先,如果您有具体的子类,那么就不会有重复的代码,但这不是您的主要问题。这取决于您如何创建子类(javassist?)您可以将它们与ObjectMapper
一起使用,也可以不使用它们,但无论如何,您都应该考虑构建一个筛选器。筛选器可以访问完整的请求,决定类型,解析输入,并存储对象,以便您可以在资源中检索它。不过,这将是非常手动的……如果有具体的子类,AIUI你的方法将导致1-1个对应的资源类,除了对我来说构成重复代码的s/cat/dog/
等,它们都是相同的。是的,手动性是我试图避免的。:-)这就是AnimalResource
的来源,你有所有的基本方法,只需将其子类化为cat,狗,任何包含@路径的东西。我会举一个简单的例子。好的,所以这里的CatResource
和DogResource
是完全重复的,除了s/cat/dog/
,这是我试图避免的。经过测试,第一次工作完美无瑕。太棒了,非常感谢!