【发布时间】:2015-06-03 19:46:04
【问题描述】:
我有一个简单的 Dropwizard 0.8.1 REST 服务,它引入了 Jersey 2.17。在 REST/Jetty 服务的上游,我有一些身份验证服务,可以向传递给我的 Dropwizard 应用程序的 HTTP 标头添加一些不错的授权信息。
我希望 喜欢 能够在我的 Resource 中创建一个自定义注释,以隐藏所有混乱的 header-parsing-to-POJO 垃圾。像这样的:
@Path("/v1/task")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TaskResource {
@UserContext // <-- custom/magic annotation
private UserContextData userContextData; // <-- holds all authorization info
@GET
public Collection<Task> fetch() {
// use the userContextData to differentiate what data to return
}
我花了最后一天环顾 stackoverflow,发现其他几个人有同样的问题并出现(?)以获得一些满足感,但我似乎无法避免得到“不在请求范围内”尝试执行此操作时的堆栈跟踪。
所以我隐藏了所有更改并尝试直接实现泽西文档第 22.1 和 22.2 节中提供的示例:https://jersey.java.net/documentation/2.17/ioc.html
按照他们的示例(但在我的 Dropwizard 应用程序中),我试图在我的资源中获取“@SessionInject”注释,但它也每次都会出现“不在请求范围内”堆栈跟踪。我在这里做错了什么?
资源:
@Path("/v1/task")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TaskResource {
private final TaskDAO taskDAO;
@Context
private HttpServletRequest httpRequest;
@SessionInject
private HttpSession httpSession;
public TaskResource(TaskDAO taskDAO) {
this.taskDAO = taskDAO;
}
@GET
public Collection<Task> fetch(@SessionInject HttpSession httpSession) {
if (httpSession != null) {
logger.info("TOM TOM TOM httpSession isn't null: {}", httpSession);
}
else {
logger.error("TOM TOM TOM httpSession is null");
}
return taskDAO.findAllTasks();
}
SessionInjectResolver:
package com.foo.admiral.integration.jersey;
import com.foo.admiral.integration.core.SessionInject;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SessionInjectResolver implements InjectionResolver<SessionInject> {
private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
@Inject
@Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
InjectionResolver<Inject> systemInjectionResolver;
@Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (HttpSession.class == injectee.getRequiredType()) {
return systemInjectionResolver.resolve(injectee, handle);
}
return null;
}
@Override
public boolean isConstructorParameterIndicator() {
return false;
}
@Override
public boolean isMethodParameterIndicator() {
return false;
}
}
HttpSessionFactory:
package com.foo.admiral.integration.jersey;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class HttpSessionFactory implements Factory<HttpSession> {
private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
private final HttpServletRequest request;
@Inject
public HttpSessionFactory(HttpServletRequest request) {
logger.info("Creating new HttpSessionFactory with request");
this.request = request;
}
@Override
public HttpSession provide() {
logger.info("Providing a new session if one does not exist");
return request.getSession(true);
}
@Override
public void dispose(HttpSession t) {
}
}
注释:
package com.foo.admiral.integration.core;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface SessionInject {
}
最后是 Dropwizard Application 类中的绑定:
@Override
public void run(TodoConfiguration configuration, Environment environment) throws Exception {
...
environment.jersey().register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(HttpSessionFactory.class).to(HttpSession.class);
bind(SessionInjectResolver.class)
.to(new TypeLiteral<InjectionResolver<SessionInject>>() { })
.in(Singleton.class);
}
});
旧堆栈跟踪:
Caused by: java.lang.IllegalStateException: Not inside a request scope.
at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149)
at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:233)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:74)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:62)
at com.sun.proxy.$Proxy72.getSession(Unknown Source)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:29)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:14)
一些可能有用的线索:
1) 我注意到我的 HttpSessionFactory 中的日志记录语句永远不会被触发,所以我认为工厂没有被正确识别到 DropWizard。
2) 如果我将注释更改为 Parameter 而不是 Field 并将注释的使用移动到 fetch( ) 方法签名中,它不会抛出堆栈跟踪(但 httpSession 仍然为 null ,大概是因为工厂没有开火……)
public Collection<Task> fetch(@SessionInject HttpSession httpSession) {
3) 如果我用 environment.jersey().register() 或 environment.jersey().getResourceConfig().register()“注册”活页夹似乎并不重要......他们似乎这样做同样的事情。
您是否发现任何明显的问题?提前致谢!
【问题讨论】:
-
我希望能够在我的资源中创建一个自定义注释来隐藏所有混乱的 header-parsing-to-POJO 垃圾你是什么意思?这个凌乱的头文件解析到 POJO 垃圾是什么?日志中是否有消息(或消息组)或类似内容?
-
我的意思是,有一个带有大 JSON blob 的 HTTP 标头,几乎每个资源和端点都需要它。我宁愿不将@HttpHeader 参数传递给每个端点方法签名,我宁愿在“幕后”进行所有 Header-JSON-to-POJO 解析。
-
您是如何将
TaskResource注册为实例或.class的?
标签: java annotations jersey dropwizard