java - 在 Jersey 2.27 中注册自定义 ValueParamProvider
问题描述
我意识到这些是内部 API,但如果它们在内部可用,为什么不让特权较低的大众使用它们,它们也非常有用。即使这些 API 在 Jersey 2.25 中是内部的,它们也可以使用,而且我想升级我的 Jersey 版本而不破坏我的自定义 Jersey 扩展。
当然可以ValueParamProvider
在 Jersey 2.27 中进行扩展,但我不再看到注册该 Provider 及其触发注释的方法。查看 Jersey 如何为其自己的实现执行此操作,它现在使用 a BoostrapConfigurator
,这似乎已被内部化到外部实现无法使用相同方法的程度。
也许我错了,如果有人清楚地描述了如何,那就太好了。否则,有人知道做同样事情的方法吗?
这曾经工作...
ResourceConfig resourcceConfig = ...
resourceConfig.register(new AbstractBinder() {
@Override
protected void configure (){
bind(MyParamValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(MyParamInjectionResolver.class).to(new TypeLiteral<InjectionResolver<EntityParam>>() {
}).in(Singleton.class);
}
}
});
通过适当的实现AbstractValueFactoryProvider
和ParamInjectionResolver
。
现在看起来你需要实现ValueParamProvider
,这很容易,但我不知道如何在 Jersey 框架中正确注册它。任何帮助表示赞赏。
解决方案
你不需要使用任何BootstrapConfigurator
. 您所需要做的就是将服务添加到注入器,它们稍后将被添加到价值提供者列表中。
要配置它,您仍然可以使用AbstractBinder
,但不要使用 HK2 ,而是使用Jersey 1。ValueParamProvider
仍然可以以相同的方式绑定,但是对于,InjectionResolver
您应该确保实现的不是 HK2 解析器,而是Jersey one。然后不是绑定到TypeLiteral
,而是绑定到GenericType
。
我只想补充一点,人们在尝试实现参数注入时存在的一个误解是,我们还需要InjectResolver
为方法参数使用自定义注释。不是这种情况。方法参数注释只是我们应该在ValueParamProvider#getValueProvider()
方法内部检查的标记注释。AnInjectResolver
仅用于非方法参数注入,例如字段和构造函数注入。如果你不需要它,那么你不需要InjectionResolver
.
下面是一个使用Jersey Test Framework的完整示例。我没有使用InjectionResolver
,只是为了表明它不是必需的。
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.server.spi.internal.ValueParamProvider;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.Response;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Function;
import static org.assertj.core.api.Assertions.assertThat;
public class ParamInjectTest extends JerseyTest {
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
}
private static class User {
private String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return this.username;
}
}
public static class AuthValueParamProvider implements ValueParamProvider {
@Override
public Function<ContainerRequest, ?> getValueProvider(Parameter parameter) {
if (parameter.getRawType().equals(User.class)
&& parameter.isAnnotationPresent(Auth.class)) {
return new UserParamProvider();
}
return null;
}
private class UserParamProvider implements Function<ContainerRequest, User> {
@Override
public User apply(ContainerRequest containerRequest) {
return new User("Peeskillet");
}
}
@Override
public PriorityType getPriority() {
return Priority.HIGH;
}
}
public static class AuthFeature implements Feature {
@Override
public boolean configure(FeatureContext context) {
context.register(new AbstractBinder() {
@Override
protected void configure() {
bind(AuthValueParamProvider.class)
.to(ValueParamProvider.class)
.in(Singleton.class);
}
});
return true;
}
}
@Path("test")
@Consumes("text/plain")
public static class TestResource {
@POST
@Produces("text/plain")
public Response post(String text, @Auth User user) {
return Response.ok(user.getUsername() + ":" + text).build();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.register(AuthFeature.class);
}
@Test
public void testIt() {
final Response response = target("test")
.request()
.post(Entity.text("Test"));
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.readEntity(String.class)).isEqualTo("Peeskillet:Test");
}
}
我要提到的另一件事是,在您扩展AbstractValueFactoryProvider
和实现 a的先前版本中ParamInjectionResolver
,大多数人这样做是为了遵循 Jersey 如何实现参数注入,同时仍然允许其他注入点(字段和构造函数)。如果您仍想使用此模式,则可以。
下面是AuthFeature
从上面的测试重构
public static class AuthFeature implements Feature {
@Override
public boolean configure(FeatureContext context) {
InjectionManager im = InjectionManagerProvider.getInjectionManager(context);
AuthValueParamProvider authProvider = new AuthValueParamProvider();
im.register(Bindings.service(authProvider).to(ValueParamProvider.class));
Provider<ContainerRequest> request = () -> {
RequestProcessingContextReference reference = im.getInstance(RequestProcessingContextReference.class);
return reference.get().request();
};
im.register(Bindings.injectionResolver(new ParamInjectionResolver<>(authProvider, Auth.class, request)));
return true;
}
}
我只是从源头中挖掘出这些东西。我在ValueParamProviderConfigurator
. 您不需要实现自己的ParamInjectionResolver
. Jersey 已经有一个具体的类,我们可以直接使用,就像上面的特性一样。
如果您TestResource
将按字段更改为注入,它现在应该可以工作
@Path("test")
@Consumes("text/plain")
public static class TestResource {
@Auth User user;
@POST
@Produces("text/plain")
public Response post(String text) {
return Response.ok(user.getUsername() + ":" + text).build();
}
}
推荐阅读
- r - R根据数字变化分离列
- javascript - 如何在javascript中查找字符串的第一个字母是否是元音
- python - 如何修复“IndexError:单个位置索引器超出范围”?
- excel - 为什么我的 Excel VBA 代码在第一次尝试时没有完全执行?
- wordpress - Divi 博客分页未在 Wordpress 上加载以前的帖子
- javascript - 如何知道哪些 CSS 属性对 HTML 元素有效
- google-apps-script - 根据变量而不是 Enum EventColor 更改 Google 日历事件颜色
- php - 找到无穷数中数字总和的第一次出现
- php - 如何从 MySql 服务器获取数据?
- javascript - Asp.Net Mvc Bootstrap 4 表单验证不会停止事件(不起作用)?