Jersey 2.0 ile bağımlılık ekleme


108

Daha önce Jersey 1.x bilgisi olmadan sıfırdan başlayarak, Jersey 2.0 projemde bağımlılık enjeksiyonunu nasıl ayarlayacağımı anlamakta zorlanıyorum.

HK2'nin Jersey 2.0'da da mevcut olduğunu anlıyorum, ancak Jersey 2.0 entegrasyonuna yardımcı olacak dokümanları bulamıyorum.

@ManagedBean
@Path("myresource")
public class MyResource {

    @Inject
    MyService myService;

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/getit")
    public String getIt() {
        return "Got it {" + myService + "}";
    }
}

@Resource
@ManagedBean
public class MyService {
    void serviceCall() {
        System.out.print("Service calls");
    }
}

pom.xml

<properties>
    <jersey.version>2.0-rc1</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<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.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey</groupId>
        <artifactId>jax-rs-ri</artifactId>
    </dependency>
</dependencies>

Konteyneri kaynağımı başlatmak ve sunmak için alabilirim, ancak @Inject'i MyService'e ekler koymaz çerçeve bir istisna atıyor:

SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
    at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)


Başlangıç ​​projem GitHub'da mevcut: https://github.com/donaldjarmstrong/jaxrs

Yanıtlar:


107

AbstractBinderJAX-RS uygulamanızda bir tanımlamanız ve kaydetmeniz gerekir. Bağlayıcı, bağımlılık enjeksiyonunun sınıflarınızı nasıl oluşturması gerektiğini belirtir.

public class MyApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(MyService.class).to(MyService.class);
    }
}

Bir @Injectparametre veya tür alanında algılandığında MyService.class, sınıf kullanılarak somutlaştırılır MyService. Bu bağlayıcıyı kullanmak için JAX-RS uygulamasına kaydedilmesi gerekir. Cihazınızda aşağıdaki web.xmlgibi bir JAX-RS uygulaması tanımlayın:

<servlet>
  <servlet-name>MyApplication</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>com.mypackage.MyApplication</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>MyApplication</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

Uygulama MyApplication(yukarıda belirtilen sınıfı init-param).

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(new MyApplicationBinder());
        packages(true, "com.mypackage.rest");
    }
}

Bağımlılık enjeksiyonunu belirten bağlayıcı, sınıfın yapıcısına kaydedilir ve ayrıca uygulamaya yöntem çağrısını MyResourcekullanarak REST kaynaklarını (sizin durumunuzda ) nerede bulacağını söyleriz packages().


1
EntityManager ne olacak? Nasıl bağlanacağına dair herhangi bir ipucu, böylece @PersistenceContext aracılığıyla enjekte edebilir miyim?
Johannes Staehlin

4
Ne olduğundan emin değilim EntityManager, ancak docs.oracle.com/javaee/6/api/javax/persistence/… 'e bakarak bir arayüz gibi görünüyor. Şu bağlantıyı kullanarak bağlayabilir bind(EntityManagerImpl.class).to(EntityManager.class)bir sınıf olarak bağlanacak olan ( EntityManagerImplarabirimini uygulayan EntityManager. Eğer bir fabrika kullanmanız gerekiyorsa, bir göz atın bindFactory()içinde AbstractBinder. Bu konuda yardıma ihtiyaç duyarsanız yeni bir soru oluşturun (ben oda olmaz Ayrıca,
@PersistentContext

Evet, EntityManager JPA'ya (Java EE) özeldir. Yorumunuz için teşekkürler, belirli bir sorunla karşılaşırsam başka bir soru açacağım!
Johannes Staehlin

Kayıt için, JPA ayrıca Java SE üzerinde de çalışıyor. oracle.com/technetwork/java/javaee/tech/…
prefabSOFT

2
Bind ne işe yarar? Ya bir arayüzüm ve uygulamam varsa?
Dejell

53

İlk önce sadece kabul edilen cevapta bir yorumu cevaplamak için.

"Bind ne işe yarar? Bir arayüze ve uygulamam varsa ne olur?"

Basitçe okur bind( implementation ).to( contract ). Alternatif zincir yapabilirsiniz .in( scope ). Varsayılan kapsam PerLookup. Yani bir singleton istiyorsanız, yapabilirsiniz

bind( implementation ).to( contract ).in( Singleton.class );

Bir de RequestScopedmevcuttur

Ayrıca, bunun yerine, otomatik olarak tekli olacak olanı bind(Class).to(Class)da yapabilirsiniz bind(Instance).to(Class).


Ekleme kabul cevap

AbstractBinderUygulamanızı web.xml dosyanıza nasıl kaydedeceklerini bulmaya çalışanlar için (yani a kullanmıyorsunuz ResourceConfig), bağlayıcı, paket taramasıyla keşfedilmeyecek gibi görünüyor, yani

<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>
        your.packages.to.scan
    </param-value>
</init-param>

Ya da bu

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>
        com.foo.YourBinderImpl
    </param-value>
</init-param>

İşe yaraması için şunu uygulamalıydım Feature:

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

@Provider
public class Hk2Feature implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        context.register(new AppBinder());
        return true;
    }
}

@ProviderEk açıklama izin vermelidir Featurepaket tarama tarafından alınmayı. Ya da paket taraması yapmadan Feature,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.classnames</param-name>
        <param-value>
            com.foo.Hk2Feature
        </param-value>
    </init-param>
    ...
    <load-on-startup>1</load-on-startup>
</servlet>

Ayrıca bakınız:

ve Jersey belgelerinden genel bilgiler için


GÜNCELLEME

Fabrikalar

Kabul edilen cevaptaki temel bağlayıcılığın yanı sıra, daha karmaşık oluşturma mantığına sahip olabileceğiniz ve ayrıca bağlam bilgisi talep etme erişimine sahip olabileceğiniz fabrikalarınız da var. Örneğin

public class MyServiceFactory implements Factory<MyService> {
    @Context
    private HttpHeaders headers;

    @Override
    public MyService provide() {
        return new MyService(headers.getHeaderString("X-Header"));
    }

    @Override
    public void dispose(MyService service) { /* noop */ }
}

register(new AbstractBinder() {
    @Override
    public void configure() {
        bindFactory(MyServiceFactory.class).to(MyService.class)
                .in(RequestScoped.class);
    }
});

Ardından MyServicekaynak sınıfınıza enjekte edebilirsiniz .


Kabul edilen yanıtta gösterildiği gibi, bağlayıcı sınıfımı yalnızca ResourceConfig uygulaması aracılığıyla kaydedebilirim. Özellik sınıfına gerek yoktu.
Patrick Koorevaar

On çağrılsa web.xmlbile kullanıldığında , kaynak istemek bir . @PaulSamsothaconfigure()Hk2FeatureNullPointerException
bytesandcaffeine

12

Seçilen cevap bir süre öncesine aittir. Her bağlamayı özel bir HK2 bağlayıcısında bildirmek pratik değildir. Tomcat kullanıyorum ve sadece bir bağımlılık eklemek zorunda kaldım. Glassfish için tasarlanmış olmasına rağmen, diğer kaplara mükemmel bir şekilde uyar.

   <dependency>
        <groupId>org.glassfish.jersey.containers.glassfish</groupId>
        <artifactId>jersey-gf-cdi</artifactId>
        <version>${jersey.version}</version>
    </dependency>

Konteynırınızın da doğru şekilde yapılandırıldığından emin olun ( belgelere bakın ).


Son satır (kapsayıcınızın da doğru şekilde yapılandırıldığından emin olun) biraz belirsiz. Burada herhangi bir yardım var mı? Nerede hangi ek açıklamaları kullanıyoruz?
markthegrea

Tomcat ile çalışmak için bazı özel yapılandırma gerektiren bağımlılık ekleme için Weld kullanıyorduk (uygulamamız "kapsayıcı"). Spring kullanıyorsanız, kutunun dışında çalışır.
otonglet

5

Geç ama umarım bu birine yardımcı olur.

JAX RS'mi şu şekilde tanımladım:

@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {

Sonra, koduma nihayet enjekte edebilirim:

@Inject
SomeManagedBean bean;

Benim durumumda, SomeManagedBeanbir ApplicationScoped fasulyesi.

Umarım bu herkese yardımcı olur.


3

Oracle, JAX-RS'yi CDI ile birleştirirken enjekte edilecek tüm türlere @Path ek açıklamasını eklemenizi önerir: http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm Bu mükemmel olmaktan uzak ( Örneğin, başlangıçta Jersey'den uyarı alacaksınız), bu rotayı izlemeye karar verdim, bu da beni bir bağlayıcı içinde desteklenen tüm türleri korumaktan kurtarıyor.

Misal:

@Singleton
@Path("singleton-configuration-service")
public class ConfigurationService {
  .. 
}

@Path("my-path")
class MyProvider {
  @Inject ConfigurationService _configuration;

  @GET
  public Object get() {..}
}

1
Bağlantı
Hank


0

AbstractBinderBenim için, web uygulamama aşağıdaki bağımlılıkları eklersem olmadan çalışır (Tomcat 8.5, Jersey 2.27 üzerinde çalışıyor):

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.ext.cdi</groupId>
    <artifactId>jersey-cdi1x</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>${jersey-version}</version>
</dependency>

Benim için CDI 1.2 / CDI 2.0 ile çalışıyor (sırasıyla Weld 2/3 kullanarak).


0

Jersey dinlendirici hizmeti için bağımlılık gereklidir ve Tomcat sunucudur. $ {jersey.version} 2.29.1

    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>2.0.SP1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>${jersey.version}</version>
    </dependency>

Temel kod aşağıdaki gibi olacaktır:

@RequestScoped
@Path("test")
public class RESTEndpoint {

   @GET
   public String getMessage() {
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.