java - Jersey Hk2 inyectando @Service clases anotadas
inject (5)
Por mi vida no puedo hacer que Jersey con hk2 descubra automáticamente las clases anotadas @Service e inyectarlas. Intenté seguir todos los consejos sobre desbordamiento de pila, jersey y documentación de hk2 y todavía no tuve suerte. Intento inyectar un servicio de eco simple en un recurso de Jersey. El esqueleto se genera a partir del arquetipo de maqueta de webapp simple para Jersey, que traté de ampliar. Esto es lo que tengo hasta ahora:
pom.xml
<build>
<finalName>sandbox</finalName>
<plugins>
<plugin>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-inhabitant-generator</artifactId>
<version>2.3.0</version>
<executions>
<execution>
<configuration>
<verbose>true</verbose>
</configuration>
<goals>
<goal>generate-inhabitants</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package.jerseytest</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.package.jerseytest.application.Application</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
my.package.jerseytest.application.Application
public class Application extends ResourceConfig {
public Application() {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
}
}
my.package.jerseytest.service.EchoService
@Service
public class EchoService {
public String generateResponse(String echo) {
return echo;
}
}
my.package.jerseytest.resource.MyResource
@Path("myresource")
public class MyResource {
@Inject
EchoService echoService;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return echoService.generateResponse("Got it!");
}
}
He comprobado que el inhibidor-generador realmente se ejecuta y produce su salida, pero cuando ejecuto el servidor Tomcat OBTENER http://localhost:8080/sandbox/webapi/myresource
obtengo
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/sandbox] threw exception [A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.jerseytest.resource.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.jerseytest.resource.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
¿Alguna idea de lo que me estoy perdiendo? Apreciaría cualquier ayuda :(
¡NÓTESE BIEN! Se acerca de
- ¿Cómo encuentra ServiceLocator @Service y @Contact automáticamente en HK2?
- Las anotaciones HK2 no están siendo manejadas
- https://hk2.java.net/inhabitant-generator.html
- https://hk2.java.net/2.2.0-b25/getting-started.html
- https://java.net/jira/browse/HK2-165
pero no me ayudaron ...
Intente agregar los paquetes que necesitan escaneados en su constructor de Aplicación. El parámetro "verdadero" en paquetes significa escanear el paquete recursivamente:
public class Application extends ResourceConfig {
public Application() {
packages(true, "my.package.jerseytest");
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
}
}
Use packages(true, "my.package.jerseytest");
Y use org.glassfish.jersey.spi.Contract
not org.jvnet.hk2.annotations.Contract
annotation. Y usa interfaces simples sin genéricos.
Intenta agregar @Stateless
@Path("myresource")
@Stateless
public class MyResource {
@Inject
EchoService echoService;
...
}
Resolví mi problema bastante así utilizando una clase que amplía AbstractBinder, instanciando y registrando con la aplicación.
resourceConfig.register(new DependencyBinder());
También,
/**
* dependency injection bindings.
* Jersey requires that service implementations are bound to their contracts this way.
*/
public final class DependencyBinder extends AbstractBinder {
@Override
protected final void configure() {
bind(StatusServiceImpl.class).to(StatusService.class);
}
}
Estoy combinando la información que obtuve de estas dos preguntas:
- ¿Cómo encuentra ServiceLocator @Service y @Contact automáticamente en HK2?
- jersey + grizzly + hk2: Inyección de dependencia, pero no en recursos
En primer lugar, use el Generador de Metadatos HK2 (o el Generador Inhabitante) en su cadena de compilación (como ya lo hace). Esto escaneará su fuente y creará META-INF/hk2-locator/default
.
En segundo lugar, crea un nuevo ServiceLocator
, poblado con los servicios de los metadatos:
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
Ahora pasa esto a Grizzly
. Citando @peeskillet :
Jersey tiene su propio ServiceLocator, y no es fácil intentar obtener una referencia. Podríamos darle a Jersey nuestro ServiceLocator, pero finalmente Jersey creará su propio localizador y lo completará con nuestro localizador.
ResourceConfig config = new MyApplicationConfig();
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
URI.create(BASE_URI),
config,
serviceLocator
);