4

Suppose Animal is an abstract class in my project, and I have a REST resource (on a JAX-RS server, using Jackson for (de)serialization) for a PUT to manipulate animals that are stored in my database. They have concrete types, and the REST resource specifies the type in the path of the request:

@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 {
    //...
}

I want to use entityType to pick the concrete class to deserialize with (Dog or Cat or whatever, for entityType being dog or cat or whatever). For reasons which are too complicated to explain here, I cannot put the type information in the JSON input itself.

So AIUI annotating Animal with a custom TypeIdResolver or something of the sort can't help me, because the type information won't be in the JSON itself (and that's all the info that the type resolver will get). I was planning to use a custom MessageBodyReader, but as far as I can tell, that doesn't get the other parameter values from the body passed in its readValue method, so I won't know what to deserialize into.

What am I missing? If this approach fails, how can I accomplish what I want without specifying animal-specific endpoints (which leads to lots of duplicate code as well as a loss of generality - right now I can add an subclass of Animal and this code will Just Work, which is very nice.)

4

2 回答 2

4

以下来自 JAX-RS 规范(5.2.2 URI 和 URI 模板)的引用表明您应该能够将UriInfo实例注入到您的 customMessageBodyReader中,并使用其中一种方法来检查请求的 URL 路径。

可以使用@Context 注解将 UriInfo 的实例注入到类字段或方法参数中。UriInfo 提供有关请求 URI 组件的静态和动态的每个请求的信息。

那里提供的示例显示了一个接收UriInfo参数的资源方法,但通常也应该可以将实例注入提供者(MessageBodyReader)。

通过 获取entityType路径参数后UriInfo,你MessageBodyReader应该可以提供对应的子类了Animal

于 2013-03-01T16:22:52.497 回答
0

鉴于您正在尝试做的事情,您最好构建一个AnimalResource包含基本方法的类,然后单独构建DogResourceCatResource以及您需要扩展的任何其他类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
}

然后,假设它们都具有相同的设置,您的个体动物很简单:

@Path("/cats")
public class CatResource extends AnimalResource<Cat>
{
    public CatResource(final CatService catService)
    {
        super(catService);
    }
}

对于一只猫和

@Path("/dogs")
public class DogResource extends AnimalResource<Dog>
{
    public DogResource(final DogService dogService)
    {
        super(dogService);
    }
}

为一只狗。它们将从父类继承标准的 CRUD 方法,并且任何特定于动物的方法仍然可以放在单独的*Resource类中。

于 2013-03-01T16:34:58.260 回答