Проблема создания простого одноэлементного класса в Jersey 2 с помощью встроенной инъекции зависимостей Jersey
У меня возникли проблемы с получением очень простой реализации синглетного класса с помощью Jersey 2 (2.7) и только встроенной в Jersey инъекции зависимостей HK2. Я проверяю это на Tomcat.
Моя цель-создать одноэлементный экземпляр класса поддержки, который будет использоваться различными методами веб-службы. У меня нет сильного предпочтения между инъекцией конструктора, инъекцией метода и аннотацией члена класса (как я делаю ниже).
Вот мой будущий синглтон. класс:
package singletest;
import javax.inject.Singleton;
@Singleton
public class JustOne {
private int secretNumber = 0;
public void hitMe(int input) {
secretNumber += input;
}
@Override
public String toString() {
return String.format("{ "secretNumber": %s }", secretNumber);
}
}
Вот мой класс приложений:
package singletest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
@ApplicationPath("/*")
public class MainApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(TestResource.class);
return classes;
}
@Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(new JustOneProvider());
return singletons;
}
}
Вот мой класс Provider/ContextResolver:
package singletest;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class JustOneProvider implements ContextResolver<JustOne> {
private static JustOne justOne = new JustOne();
@Override
public JustOne getContext(Class<?> type) {
return justOne;
}
}
Паутина.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>singletest.MainApplication</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>singletest.MainApplication</param-value>
</init-param>
<!-- pass to next filter if Jersey/App returns 404 -->
<init-param>
<param-name>jersey.config.servlet.filter.forwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>singletest.MainApplication</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Ресурс, в который я намереваюсь ввести синглетный экземпляр моего класса JustOne:
package singletest;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/test")
public class TestResource {
@Inject
private JustOne justOne;
@GET
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
@Path("/func1/{input}")
public Response func1(@PathParam("input") int input) {
justOne.hitMe(input);
String responseData = justOne.toString();
return Response.ok(responseData).build();
}
}
Это предупреждение возникает, когда война развертывается / инициализируется в Джерси:
Apr 28, 2014 11:48:25 AM org.glassfish.jersey.server.ApplicationHandler initialize
INFO: Initiating Jersey application, version Jersey: 2.7 ${buildNumber}...
Apr 28, 2014 11:48:25 AM org.glassfish.jersey.internal.inject.Providers checkProviderRuntime
WARNING: A provider java.lang.Class registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider java.lang.Class will be ignored.
И ошибка, которую я получаю, когда вызываю этот веб-сервис:
type Exception report
message A MultiException has 3 exceptions. They are:
description The server encountered an internal error that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=JustOne,parent=TestResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,58952407)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of singletest.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on singletest.TestResource
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:333)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Итак, я понял: hk2 не получает достаточно информации для создания / привязки JustOne экземпляр и/или найти / использовать мой JustOneProvider. Я уверен, что упускаю что-то основное. Любое руководство будет оценено.
2 ответа:
bind(JustOne.class).to(JustOne.class).in(Singleton.class);
- это самая важная часть. Без "в (Синглтон.класс) " будет создано несколько экземпляров JustOne.
Хорошо, потратив на это очень здоровый кусок времени, я заработал его.
Я использовал HK2 AbstractBinder и JAX-РТС Характеристика (класса javax.с WS.РС.ядро.Характеристика).
Оказалось, что никакой поставщик / ContextResolver не требуется.
Применение:
import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import java.util.HashSet; import java.util.Set; @ApplicationPath("/*") public class MainApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(TestResource.class); classes.add(JustOneFeature.class); return classes; } }
Класс To-be-singleton:
public class JustOne { private int secretNumber = 0; public int getSecretNumber() { return secretNumber; } public void bumpSecretNumber() { secretNumber += 1; } }
Связующее:
import org.glassfish.hk2.utilities.binding.AbstractBinder; public class JustOneBinder extends AbstractBinder { @Override protected void configure() { bind(new JustOne()).to(JustOne.class); } }
Характеристика:
import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; public class JustOneFeature implements Feature { @Override public boolean configure(final FeatureContext context) { context.register(new JustOneBinder()); return true; } }
Ресурс, в который вводится синглетон:
import javax.inject.Inject; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("/test") public class TestResource { @Inject private JustOne justOne; @GET @Consumes(MediaType.TEXT_PLAIN) @Produces(MediaType.APPLICATION_JSON) @Path("/func1/{input}") public Response func1(@PathParam("input") int input) { justOne.bumpSecretNumber(); String responseData = String.format("{ \"result\": %s }", input + justOne.getSecretNumber()); return Response.ok(responseData).build(); } }