Sye*_*yed 5 java rest dropwizard jersey-2.0 hk2
您好我正在使用dropwizard构建一个应用程序,即在内部使用jersey 2.16作为REST API框架.
对于所有资源方法的整个应用程序,我需要一些信息,以便解析我定义了自定义过滤器的信息,如下所示
@java.lang.annotation.Target(ElementType.PARAMETER)
@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
public @interface TenantParam {
}
Run Code Online (Sandbox Code Playgroud)
租户工厂定义如下
public class TenantFactory implements Factory<Tenant> {
private final HttpServletRequest request;
private final ApiConfiguration apiConfiguration;
@Inject
public TenantFactory(HttpServletRequest request, @Named(ApiConfiguration.NAMED_BINDING) ApiConfiguration apiConfiguration) {
this.request = request;
this.apiConfiguration = apiConfiguration;
}
@Override
public Tenant provide() {
return null;
}
@Override
public void dispose(Tenant tenant) {
}
}
Run Code Online (Sandbox Code Playgroud)
我实际上没有实现该方法,但结构在上面.还有一个TenantparamResolver
public class TenantParamResolver implements InjectionResolver<TenantParam> {
@Inject
@Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
private InjectionResolver<Inject> systemInjectionResolver;
@Override
public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
if(Tenant.class == injectee.getRequiredType()) {
return systemInjectionResolver.resolve(injectee, serviceHandle);
}
return null;
}
@Override
public boolean isConstructorParameterIndicator() {
return false;
}
@Override
public boolean isMethodParameterIndicator() {
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
现在在我的资源方法中,我正在做如下
@POST
@Timed
public ApiResponse create(User user, @TenantParam Tenant tenant) {
System.out.println("resource method invoked. calling service method");
System.out.println("service class" + this.service.getClass().toString());
//DatabaseResult<User> result = this.service.insert(user, tenant);
//return ApiResponse.buildWithPayload(new Payload<User>().addObjects(result.getResults()));
return null;
}
Run Code Online (Sandbox Code Playgroud)
以下是我配置应用程序的方法
@Override
public void run(Configuration configuration, Environment environment) throws Exception {
// bind auth and token param annotations
environment.jersey().register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(TenantFactory.class).to(Tenant.class);
bind(TenantParamResolver.class)
.to(new TypeLiteral<InjectionResolver<TenantParam>>() {})
.in(Singleton.class);
}
});
}
Run Code Online (Sandbox Code Playgroud)
问题是在应用程序启动期间我遇到了错误
WARNING: No injection source found for a parameter of type public void com.proretention.commons.auth.resources.Users.create(com.proretention.commons.api.core.Tenant,com.proretention.commons.auth.model.User) at index 0.
Run Code Online (Sandbox Code Playgroud)
并且有很长的堆栈错误堆栈和描述
以下是用户pojo的声明签名
public class User extends com.company.models.Model {
用户类没有注释.Model是一个类,它只定义long类型的单个属性id,并且在模型类上也没有注释
当我从上面创建资源方法中删除User参数时,它工作正常,当我删除TenantParam时,它也可以正常工作.只有在我同时使用User和TenantParam时才会出现此问题
EDITED
我刚尝试了两个自定义方法param注入,这也是行不通的
@POST
@Path("/login")
@Timed
public void validateUser(@AuthParam AuthToken token, @TenantParam Tenant tenant) {
}
Run Code Online (Sandbox Code Playgroud)
注入的方法参数的处理方式略有不同。我们需要为此实现的组件是ValueFactoryProvider
. 一旦你实现了它,你还需要将它绑定到你的AbstractBinder
.
泽西岛有一个用于实施ValueFactoryProvider
. @PathParam
这是用于处理和 等参数的模式@QueryParam
。ValueFactoryProvider
泽西岛为其中每一项以及其他方面都有一个。
模式如下:
ValueFactoryProvider
我们不是直接实现,而是扩展AbstractValueFactoryProvider
public static class TenantValueProvider extends AbstractValueFactoryProvider {
@Inject
public TenantValueProvider(MultivaluedParameterExtractorProvider mpep,
ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
@Override
protected Factory<?> createValueFactory(Parameter parameter) {
if (!parameter.isAnnotationPresent(TenantParam.class)
|| !Tenant.class.equals(parameter.getRawType())) {
return null;
}
return new Factory<Tenant>() {
@Override
public Tenant provide() {
...
}
};
}
Run Code Online (Sandbox Code Playgroud)
在这个组件中,它有一个我们需要实现的方法,该方法返回Factory
提供方法参数值的方法。
这InjectionResolver
是用来处理自定义注释的。使用这种模式,我们不需要像OP那样直接实现它,而是将ParamInjectionResolver
我们的AbstractValueFactoryProvider
实现类传递给超级构造函数
public static class TenantParamInjectionResolver
extends ParamInjectionResolver<TenantParam> {
public TenantParamInjectionResolver() {
super(TenantValueProvider.class);
}
}
Run Code Online (Sandbox Code Playgroud)确实如此。然后只需绑定两个组件即可
public static class Binder extends AbstractBinder {
@Override
public void configure() {
bind(TenantParamInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<TenantParam>>(){})
.in(Singleton.class);
bind(TenantValueProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
}
}
Run Code Online (Sandbox Code Playgroud)
下面是使用Jersey Test Framework 的完整测试。javadoc 注释中列出了所需的依赖项。您可以像任何其他 JUnit 测试一样运行该测试
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.logging.Logger;
import javax.inject.Inject;
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.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
import org.glassfish.jersey.server.internal.inject.ParamInjectionResolver;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.server.spi.internal.ValueFactoryProvider;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Stack Overflow /sf/ask/2040206521/
*
* Run this like any other JUnit test. Dependencies required are as the following
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
* <version>2.22</version>
* <scope>test</scope>
* </dependency>
* <dependency>
* <groupId>org.glassfish.jersey.media</groupId>
* <artifactId>jersey-media-json-jackson</artifactId>
* <version>2.22</version>
* <scope>test</scope>
* </dependency>
*
* @author Paul Samsotha
*/
public class TenantInjectTest extends JerseyTest {
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public static @interface TenantParam {
}
public static class User {
public String name;
}
public static class Tenant {
public String name;
public Tenant(String name) {
this.name = name;
}
}
public static class TenantValueProvider extends AbstractValueFactoryProvider {
@Inject
public TenantValueProvider(MultivaluedParameterExtractorProvider mpep,
ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
@Override
protected Factory<?> createValueFactory(Parameter parameter) {
if (!parameter.isAnnotationPresent(TenantParam.class)
|| !Tenant.class.equals(parameter.getRawType())) {
return null;
}
return new AbstractContainerRequestValueFactory<Tenant>() {
// You can @Inject things here if needed. Jersey will inject it.
// for example @Context HttpServletRequest
@Override
public Tenant provide() {
final ContainerRequest request = getContainerRequest();
final String name
= request.getUriInfo().getQueryParameters().getFirst("tenent");
return new Tenant(name);
}
};
}
public static class TenantParamInjectionResolver
extends ParamInjectionResolver<TenantParam> {
public TenantParamInjectionResolver() {
super(TenantValueProvider.class);
}
}
public static class Binder extends AbstractBinder {
@Override
public void configure() {
bind(TenantParamInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<TenantParam>>(){})
.in(Singleton.class);
bind(TenantValueProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
}
}
}
@Path("test")
@Produces("text/plain")
@Consumes("application/json")
public static class TestResource {
@POST
public String post(User user, @TenantParam Tenant tenent) {
return user.name + ":" + tenent.name;
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(TestResource.class)
.register(new TenantValueProvider.Binder())
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
@Test
public void shouldReturnTenantAndUserName() {
final User user = new User();
user.name = "peeskillet";
final Response response = target("test")
.queryParam("tenent", "testing")
.request()
.post(Entity.json(user));
assertEquals(200, response.getStatus());
assertEquals("peeskillet:testing", response.readEntity(String.class));
}
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
归档时间: |
|
查看次数: |
4034 次 |
最近记录: |