2014-10-07 10 views
6

Für das Leben von mir kann ich Jersey mit hk2 nicht bekommen, @Service annotierte Klassen automatisch zu entdecken und sie zu injizieren. Ich habe versucht, alle Ratschläge zu Stapelüberlauf, Trikot und hk2 Dokumentation zu befolgen und immer noch kein Glück. Ich versuche, einen einfachen Echo-Service in eine Jersey-Ressource zu injizieren. Das Skelett wird aus dem einfachen Webapp-Maven-Archetyp für Jersey generiert, den ich zu erweitern versuchte. Das ist, was ich habe, so weit:Jersey Hk2 injecting @Service annotierte Klassen

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(); 
    } 
} 

meine. 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!"); 
    } 
} 

Ich habe überprüft, dass der inhibitant-Generator in der Tat laufen und dessen Ausgang erzeugen, doch wenn der Server SCHRITTE http://localhost:8080/sandbox/webapi/myresource Tomcat läuft ich

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) 

Irgendwelche Ideen, die ich vermisse? Ich würde schätzen jede Hilfe :(

NB! Ich weiß, über

aber sie haben mir nicht geholfen ...

+1

etwas Glück dazu? –

+1

Nein, gab auf. Es gab etwas über zwei verschiedene Versionen der @Inject-Annotation, aber das Projekt ging an diesem vorbei und wir entschieden uns für die Spring Bridge von Spring und den Spring DI-Container. –

+0

Nur neugierig, warum nicht einfach CDI? – ymajoros

Antwort

0

Versuchen Sie, die Pakete hinzuzufügen, die in Ihrem Anwendungskonstruktor gescannt werden müssen. Die „wahre“ Parameter auf Pakete bedeutet das Paket rekursiv zu scannen:

public class Application extends ResourceConfig { 
    public Application() { 
     packages(true, "my.package.jerseytest"); 
     ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator(); 
    } 
} 
+0

Versucht, sorry, ich bekomme immer noch die gleiche Ausnahme. Ich frage mich nur: Wenn die Namen der Klassen, die injiziert werden sollen, vom Einwohner-Generator in einer Datei gesammelt werden, warum muss ich dann Pakete scannen? –

0

Verwenden packages(true, "my.package.jerseytest"); Und org.glassfish.jersey.spi.Contract nicht org.jvnet.hk2.annotations.Contract Anmerkung verwenden. Und verwenden Sie einfache Schnittstellen ohne Generika.

+0

Versucht mit und ohne eine passende @Contract annotierte Schnittstelle zum Dienst, hat nicht geholfen. Wenn ich die Dokumentation richtig verstanden habe, ist es nicht notwendig, eine Schnittstelle für den Dienst zu haben (obwohl ich es aus einem sauberen Code Sicht es ist schön zu bekommen) –

0

Versuchen Zugabe @Stateless

@Path("myresource") 
@Stateless 
public class MyResource { 
    @Inject 
    EchoService echoService; 
... 
} 
+0

Hallo, danke für die Antwort ... wir haben ging mit dem Projekt weiter und gab schließlich hk2 auf; stattdessen verlassen wir uns auf Federbrücke und Feder für DI. –

+0

Wie war die Entscheidung, Spring Bridge und Spring DI zu verwenden? Irgendwelche Reue? – Raf

+0

Einer der Vorteile von Feder ist, unabhängig vom Behälter zu sein. Sie werden keinen Unterschied bei der Verwendung von Glassfish, Wildfly oder Tomcat zum Beispiel sehen. –

1

ich die Kombination der Einsicht, die ich aus diesen beiden Fragen gewonnen:

Zuerst benutzen Sie die HK2 Metadata Generator (oder der Einwohner Gener ator) in Ihrer Baukette (wie Sie es schon tun). Dies scannt Ihre Quelle und erstellt META-INF/hk2-locator/default.

Zweitens erstellen Sie eine neue ServiceLocator, mit den Leistungen aus den Metadaten bevölkert:

ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator(); 

Jetzt Pass es zu Grizzly. Quoting @peeskillet:

Jersey hat seinen eigenen ServiceLocator, und es ist nicht einfach zu versuchen, einen Verweis darauf zu erhalten. Wir könnten Jersey unseren ServiceLocator geben, aber Jersey erstellt letztendlich immer noch seinen eigenen Locator und wird ihn mit unserem Locator füllen.

ResourceConfig config = new MyApplicationConfig(); 
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
    URI.create(BASE_URI), 
    config, 
    serviceLocator 
); 
1

löste ich mein Problem ganz wie diese durch eine Klasse verwenden, die AbstractBinder erstreckt, es instanziieren und es mit der Anwendung registrieren.

resourceConfig.register(new DependencyBinder()); 

Auch

/** 
* 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); 
    } 
} 
+2

Vorsicht! Wer diese Lösung verwendet, sollte nicht versuchen, sie generisch zu machen. Wir haben das versucht und zwei Konstruktorparameter zu dieser Art von Binder hinzugefügt. Das Ergebnis war schrecklich. Jersey registrierte nur die erste Instanz basierend auf der Klassenart.So würde der erste DependencyBinder injiziert werden, aber danach alles zurückgewiesen, weil er bereits nach Trikot hinzugefügt wurde. – JSONStatham