Jak skonfigurować aplikację JAX-RS za pomocą samych adnotacji (bez web.xml)?

80

Czy można skonfigurować aplikację JAX-RS tylko przy użyciu adnotacji? (przy użyciu Servlet 3.0 i JAX-RS Jersey 1.1.0)

Próbowałem i nie miałem szczęścia. Korzystanie z niektórych web.xmlwydaje się wymagane.


Konfiguracja A (działa, ale ma konfigurację web.xml)

web.xml

   ...
   <servlet>
      <servlet-name>org.foo.rest.MyApplication</servlet-name>
   </servlet>
   <servlet-mapping>
       <servlet-name>org.foo.rest.MyApplication</servlet-name>
       <url-pattern>/*</url-pattern>
   </servlet-mapping>
   ...

Jawa

@ApplicationPath("/")
public class MyApplication extends Application {
    ...
}

Konfiguracja B (nie działa, zgłoszony wyjątek)

@ApplicationPath("/")
@WebServlet("/*") // <-- 
public class MyApplication extends Application {
    ...
}

Ten ostatni wydaje się nalegać, że aplikacja będzie podklasą serwletu (wyjątek nie pozostawia domysłów)

java.lang.ClassCastException: org.foo.rest.MyApplication cannot be cast to javax.servlet.Servlet

pytania

  1. Dlaczego definicja web.xml zadziałała, a adnotacja nie? Co za różnica?

  2. Czy jest sposób, aby to zadziałało, np. Mieć aplikację JAX-RS bez pliku web.xml?

Eran Medan
źródło
1
Jeśli możesz spróbować z NetBeans, istnieje kreator do tworzenia usług internetowych RESTFul. Wygląda na to, że to, co próbujesz zrobić, jest tym, co robi ten kreator w wersji 6.8. Używam wersji 7.0.1, a nowe podejście jest prostsze, ale do tego celu używa jednego serwletu, czyli com.sun.jersey.spi.container.servlet.ServletContainer, ale zostało to zdefiniowane w
pliku

Odpowiedzi:

168

** PRZECZYTAJ, JEŚLI UŻYWASZ TOMCAT LUB JETTY! **

Odpowiedź Zaakceptowany ma pracy, ale tylko wtedy, gdy jest wdrożony webapp do serwera aplikacji, takich jak GlassFish lub JBoss Application Server i ewentualnie serwletów pojemników z rozszerzeniami EE jak TomEE. To nie działa na standardowych kontenerach serwletów jak Tomcat, którego jestem pewien, że większość ludzi szuka rozwiązania tutaj chcesz użyć.

Jeśli używasz standardowej instalacji Tomcat (lub innego kontenera serwletów), musisz dołączyć implementację REST, ponieważ Tomcat jej nie zawiera. Jeśli używasz Mavena, dodaj to do dependenciessekcji:

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.bundles</groupId>
    <artifactId>jaxrs-ri</artifactId>
    <version>2.13</version>
  </dependency>
  ...
</dependencies>

Następnie po prostu dodaj klasę konfiguracji aplikacji do swojego projektu. Jeśli nie masz żadnych specjalnych potrzeb konfiguracyjnych poza ustawieniem ścieżki kontekstu dla pozostałych usług, klasa może być pusta. Po dodaniu tej klasy nie musisz niczego konfigurować web.xml(lub w ogóle ją mieć):

package com.domain.mypackage;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest") // set the path to REST web services
public class ApplicationConfig extends Application {}

Następnie deklarowanie usług internetowych jest proste przy użyciu standardowych adnotacji JAX-RS w klasach Java:

package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;

// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
@Path("calc/1.0")
public class CalculatorV1_0 {
  @GET
  @Consumes("text/plain")
  @Produces("text/plain")
  @Path("addTwoNumbers")
  public String add(@MatrixParam("firstNumber") int n1, @MatrixParam("secondNumber") int n2) {
    return String.valueOf(n1 + n2);
  }
}

To powinno wystarczyć. Jeśli twoja instalacja Tomcat działa lokalnie na porcie 8080 i wdrażasz plik WAR w kontekście myContext, przechodzisz do ...

http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3

... powinien przynieść oczekiwany rezultat (5).

Alvin Thompson
źródło
6
@JavaDude - Musisz skonfigurować Mavena, aby zbudował plik WAR, nawet jeśli web.xmlnie ma go. W twojej pom.xmlmocy „build> Wtyczki”, dodać (jeśli jeszcze nie istnieje) <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>2.3</version><configuration><failOnMissingWebXml>false</failOnMissingWebXml></configuration></plugin>.
Alvin Thompson,
6
@JavaDude - ważna część to <failOnMissingWebXml>false</fai‌​lOnMissingWebXml>opcja.
Alvin Thompson
3
@JavaDude - Jeśli to nie wszystko, prawdopodobnie nie utworzyłeś klasy, która rozszerza Applicationi nie dodałeś @ApplicationPathdo niej adnotacji. Klasa może być pusta, ale musi tam być.
Alvin Thompson
3
Wystarczy tylko dodać jersey-container-servlet, bez ciągnięcia całej jaxrs-rizależności. Np. W moim przypadku był to 'org.glassfish.jersey.core:jersey-server:2.18'+ 'org.glassfish.jersey.containers:jersey-container-servlet:2.18'.
leveluptor
3
Ponieważ pytanie jest wyraźnie oznaczone jako „java-ee”, nie rozumiem zamieszania związanego z udzielaniem i głosowaniem za odpowiedzią, która NIE dotyczy środowiska jee. -1
Jan Galiński
51

Wygląda na to, że wszystko, co musiałem zrobić, to to (Servlet 3.0 i nowsze)

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/*")
public class MyApplication extends Application {
    ...
}

I najwyraźniej nie była potrzebna żadna konfiguracja web.xml (próbowano na Tomcat 7)

Eran Medan
źródło
1
Nie rozumiesz, jak to działa, możesz użyć tylko adnotacji bez żadnej innej konfiguracji? Próbowałem w ten sposób i nadal nie działam ...
Filipe
2
@Filipe: Domyślam się, że używasz Tomcata lub innego kontenera serwletów. To właściwie nie działa na kontenerach serwletów, takich jak Tomcat - działa tylko z serwerami aplikacji, takimi jak Glassfish lub Wildfly, a może TomEE. Jeśli używasz Tomcat, zobacz moją (późną) odpowiedź poniżej.
Alvin Thompson
8
Ta odpowiedź NIE działa w przypadku Tomcat ani Jetty! Zobacz moją odpowiedź, aby wszystko działało w tych (i innych) kontenerach serwletów.
Alvin Thompson,
1
W zależności od implementacji, ty nie potrzebujesz web.xml, chociaż pusta jeden wystarczy. Zobacz docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/…
Benjamin Maurer
Działa to w przypadku produktu WebSphere Liberty, ale nie w przypadku produktów WebSphere 8.x i 9.0 Classic.
Archimedes Trajano
15

Rozdział 2 specyfikacji JAX-RS: Java ™ API for RESTful Web Services opisuje proces publikacji aplikacji JAX-RS w środowisku Servlet (sekcja 2.3.2 Servlet w specyfikacji).

Należy pamiętać, że środowisko Servlet 3 jest zalecane tylko (sekcja 2.3.2 Servlet, strona 6):

ZALECA SIĘ implementacje obsługujące mechanizm podłączania struktury Servlet 3, aby umożliwić przenoszenie między kontenerami i korzystać z dostarczanych przez kontener funkcji skanowania klas.

Krótko mówiąc, jeśli chcesz zastosować podejście bez web.xml, jest to możliwe dzięki niestandardowej implementacji aplikacji javax.ws.rs.core.Application, która rejestruje zasoby usługi RESTful z adnotacją javax.ws.rs.ApplicationPath .

@ApplicationPath("/rest")

Chociaż pytałeś konkretnie o Jersey, możesz również przeczytać artykuł Implementing RESTful services with JAX-RS i WebSphere 8.5 Liberty Profile, w którym opisałem proces publikacji no-web.xml dla WebSphere Liberty Profile (z Apache Wink jako implementacją JAX-RS).

Jacek Laskowski
źródło
1
Dzięki! Mam inne pytanie mocno związane z tym, które doprowadza mnie do szału. Czy istnieje sposób, aby ścieżkę w katalogu głównym (np. @ApplicationPath ("/ *")) nadal obsługiwać JSP tylko przy użyciu adnotacji? (chociaż nawet z konfiguracją web.xml nie mogłem tego zrobić) - pytanie jest tutaj: stackoverflow.com/questions/10874188/… , ponieważ wydaje się, że znasz całkiem dobrze JAX-RS, czy mógłbyś rzucić okiem? :) może zobaczysz, czego mi brakuje ... dzięki!
Eran Medan
Nie wiem Odczucia podpowiadają mi, że powinno działać bez dodatkowej konfiguracji, ponieważ proces rozwiązywania zasobu w celu obsługi żądania przebiega od dokładnego dopasowania do wzorców adresów URL. Spojrzę i odpowiem. Dziękuję za zachęcenie mnie do poszerzania wiedzy! :-)
Jacek Laskowski
Używam @ApplicationPath("")usług REST w katalogu głównym (względem katalogu głównego aplikacji sieci Web) na JBoss EAP 7. Nie mam beans.xmlani web.xml.
Julien Kronegg
7

Musisz ustawić odpowiednie zależności w pom.xml

<dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
    </dependency>

Więcej szczegółów tutaj: Przykład startowy dla jax-rs

ACV
źródło
czy mogę usunąć plik web.xml, jeśli używany jest element ResourceConfig / aplikacja?
BAE
tak, ale musisz to dodać w pom.xml i fusnig mave:<failOnMissingWebXml>
ACV
dzięki. ale czy jest coś, co web.xml może zrobić, ale ResourceConfig nie może?
BAE
Nie, myślę, że ponieważ specyfikacja serwletu 3.0 web.xml nie jest już wymagana. Czasami jednak wygodniej jest używać pliku web.xml, ponieważ nie wymaga on ponownej kompilacji, jeśli chcesz coś zmienić.
ACV
A co jeśli nie używasz Mavena ? Mój projekt jest teraz za duży, by wrócić.
TheRealChx101
1

Wspomniane wcześniej zależności nie działają u mnie. Z podręcznika użytkownika Jersey:

Jersey zapewnia dwa moduły serwletów. Pierwszym modułem jest podstawowy moduł serwletów Jersey, który zapewnia podstawową obsługę integracji serwletów i jest wymagany w każdym kontenerze Servlet 2.5 lub nowszym:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet-core</artifactId>
</dependency>

Aby zapewnić obsługę dodatkowych trybów wdrażania Servlet 3.x i asynchronicznego modelu programowania zasobów JAX-RS, wymagany jest dodatkowy moduł Jersey:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet</artifactId>
</dependency>

Moduł jersey-container-servlet zależy od modułu jersey-container-servlet-core, dlatego gdy jest używany, nie jest konieczne jawne deklarowanie zależności jersey-container-servlet-core.

https://jersey.github.io/documentation/latest/deployment.html#deployment.servlet.3

bzak
źródło
0

Jak zauważył @ Eran-Medan, JBoss EAP 7.1 (uwaga bez aplikacji internetowej, więc bez serwletu, robiłem to w projekcie EJB 3.2) musiałem dodać atrybut „value” jako taki, ponieważ otrzymałem wyjątek, że atrybut wartości był wymagany.

To zadziałało dla mnie

    @ApplicationPath(value="/*")
        public class MyApplication extends Application {

            private Set singletons = new HashSet();

            public MyApplication() {
                singletons.add(new MyService());
            }

            ...
    }

Ślad stosu

    Caused by: java.lang.annotation.IncompleteAnnotationException: javax.ws.rs.ApplicationPath missing element value
        at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:80)
        at com.sun.proxy.$Proxy141.value(Unknown Source)
        ... 21 more
JGlass
źródło