gpt4 book ai didi

java - 使用 JAX-RS 保持干燥

转载 作者:IT老高 更新时间:2023-10-28 20:21:33 25 4
gpt4 key购买 nike

我正在尝试尽量减少许多 JAX-RS 资源处理程序的重复代码,所有这些都需要一些相同的路径和查询参数。每个资源的基本 url 模板如下所示:

/{id}/resourceName

并且每个资源都有多个子资源:

/{id}/resourceName/subresourceName

因此,资源/子资源路径(包括查询参数)可能看起来像

/12345/foo/bar?xyz=0
/12345/foo/baz?xyz=0
/12345/quux/abc?xyz=0
/12345/quux/def?xyz=0

资源 fooquux 的共同部分是 @PathParam("id")@QueryParam("xyz")。我可以像这样实现资源类:

// FooService.java
@Path("/{id}/foo")
public class FooService
{
@PathParam("id") String id;
@QueryParam("xyz") String xyz;

@GET @Path("bar")
public Response getBar() { /* snip */ }

@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
@Path("/{id}/quux")
public class QuxxService
{
@PathParam("id") String id;
@QueryParam("xyz") String xyz;

@GET @Path("abc")
public Response getAbc() { /* snip */ }

@GET @Path("def")
public Response getDef() { /* snip */ }
}

我已经设法避免在每个 get* 方法中重复注入(inject)参数。1 这是一个好的开始,但我希望能够避免跨资源类的重复。与 CDI 一起使用的方法(我也需要)是使用 abstract 基类 FooServiceQuuxService 可以 extend:

// BaseService.java
public abstract class BaseService
{
// JAX-RS injected fields
@PathParam("id") protected String id;
@QueryParam("xyz") protected String xyz;

// CDI injected fields
@Inject protected SomeUtility util;
}
// FooService.java
@Path("/{id}/foo")
public class FooService extends BaseService
{
@GET @Path("bar")
public Response getBar() { /* snip */ }

@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
@Path("/{id}/quux")
public class QuxxService extends BaseService
{
@GET @Path("abc")
public Response getAbc() { /* snip */ }

@GET @Path("def")
public Response getDef() { /* snip */ }
}

get* 方法中,CDI 注入(inject)(奇迹般地)正常工作:util 字段不为空。不幸的是,JAX-RS 注入(inject)不起作用idxyzFooServiceget* 方法中的 null >QuuxService.

是否有解决此问题的方法或解决方法?

鉴于 CDI 可以按我的意愿工作,我想知道将 @PathParams (等)注入(inject)子类的失败是错误还是 JAX 的一部分-RS 规范。


我已经尝试过的另一种方法是使用 BaseService 作为单一入口点,根据需要委托(delegate)给 FooServiceQuuxService。这基本上如 RESTful Java with JAX-RS 中所述。使用子资源定位器。

// BaseService.java
@Path("{id}")
public class BaseService
{
@PathParam("id") protected String id;
@QueryParam("xyz") protected String xyz;
@Inject protected SomeUtility util;

public BaseService () {} // default ctor for JAX-RS

// ctor for manual "injection"
public BaseService(String id, String xyz, SomeUtility util)
{
this.id = id;
this.xyz = xyz;
this.util = util;
}

@Path("foo")
public FooService foo()
{
return new FooService(id, xyz, util); // manual DI is ugly
}

@Path("quux")
public QuuxService quux()
{
return new QuuxService(id, xyz, util); // yep, still ugly
}
}
// FooService.java
public class FooService extends BaseService
{
public FooService(String id, String xyz, SomeUtility util)
{
super(id, xyz, util); // the manual DI ugliness continues
}

@GET @Path("bar")
public Response getBar() { /* snip */ }

@GET @Path("baz")
public Response getBaz() { /* snip */ }
}
// QuuxService.java
public class QuuzService extends BaseService
{
public FooService(String id, String xyz, SomeUtility util)
{
super(id, xyz, util); // the manual DI ugliness continues
}

@GET @Path("abc")
public Response getAbc() { /* snip */ }

@GET @Path("def")
public Response getDef() { /* snip */ }
}

这种方法的缺点是 CDI 注入(inject)和 JAX-RS 注入(inject)都不能在子资源类中工作。这样做的原因是相当明显的2,但是的意思是我必须手动将字段重新注入(inject)子类的构造函数中,这很困惑,很难看,并且不容易让我自定义进一步的注入(inject)。示例:假设我想将一个实例 @Inject 放入 FooService 而不是 QuuxService。因为我是显式实例化BaseService的子类,所以CDI注入(inject)不起作用,所以丑的继续。


tl;dr 避免跨 JAX-RS 资源处理程序类重复注入(inject)字段的正确方法是什么?

为什么 JAX-RS 不注入(inject)继承字段,而 CDI 对此没有问题?


编辑 1

来自@Tarlog 的一些指导,我想我已经找到了我的一个问题的答案,

Why aren't inherited fields injected by JAX-RS?

JSR-311 §3.6 :

If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the super class or interface method are ignored.

我确信这个决定是有真正的原因的,但不幸的是,在这个特定的用例中,这个事实对我不利。我仍然对任何可能的解决方法感兴趣。


1 使用字段级注入(inject)的警告是,我现在绑定(bind)到每个请求的资源类实例化,但我可以忍受。
2 因为我是调用 new FooService() 而不是容器/JAX-RS 实现的人。

最佳答案

这是我正在使用的解决方法:

使用 'id' 和 'xyz' 作为参数为 BaseService 定义一个构造函数:

// BaseService.java
public abstract class BaseService
{
// JAX-RS injected fields
protected final String id;
protected final String xyz;

public BaseService (String id, String xyz) {
this.id = id;
this.xyz = xyz;
}
}

使用注入(inject)在所有子类上重复构造函数:

// FooService.java
@Path("/{id}/foo")
public class FooService extends BaseService
{
public FooService (@PathParam("id") String id, @QueryParam("xyz") String xyz) {
super(id, xyz);
}

@GET @Path("bar")
public Response getBar() { /* snip */ }

@GET @Path("baz")
public Response getBaz() { /* snip */ }
}

关于java - 使用 JAX-RS 保持干燥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5875772/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com