Wie richte ich die JAX-RS-Anwendung nur mit Anmerkungen ein (keine web.xml)?

80

Ist es möglich, eine JAX-RS-Anwendung nur mit Anmerkungen einzurichten? (mit Servlet 3.0 und JAX-RS Jersey 1.1.0)

Ich habe es versucht und hatte kein Glück. Einige zu verwenden web.xmlscheint erforderlich.


Konfiguration A (funktioniert, hat aber die Konfiguration 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>
   ...

Java

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

Konfiguration B (funktioniert nicht, Ausnahme ausgelöst)

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

Letzterer scheint darauf zu bestehen, dass die Anwendung eine Unterklasse von Servlet sein wird (die Ausnahme lässt keine Vermutungen zu)

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

Fragen

  1. Warum hat die Definition von web.xml funktioniert, die Anmerkung jedoch nicht? Was ist der Unterschied?

  2. Gibt es eine Möglichkeit, es zum Laufen zu bringen, z. B. eine JAX-RS-Anwendung ohne web.xml?

Eran Medan
quelle
1
Wenn Sie es mit NetBeans versuchen können, gibt es einen Assistenten zum Erstellen von RESTFul-Webdiensten. Es scheint, dass Sie versuchen, das zu tun, was dieser Assistent in Version 6.8 tut. Ich verwende 7.0.1 und der neue Ansatz ist einfacher, verwendet jedoch ein einzelnes Servlet für diesen Zweck, nämlich com.sun.jersey.spi.container.servlet.ServletContainer, aber es ist in web.xml definiert
perissf

Antworten:

168

** BITTE LESEN SIE, WENN SIE TOMCAT ODER JETTY VERWENDEN! ** **.

Die akzeptierte Antwort funktioniert , jedoch nur, wenn die Webanwendung auf einem App-Server wie Glassfish oder Wildfly und möglicherweise auf Servlet-Containern mit EE-Erweiterungen wie TomEE bereitgestellt wird. Es funktioniert nicht mit Standard-Servlet-Containern wie Tomcat, die sicher die meisten Leute, die hier nach einer Lösung suchen, verwenden möchten.

Wenn Sie eine Standardinstallation von Tomcat (oder einen anderen Servlet-Container) verwenden, müssen Sie eine REST-Implementierung einschließen, da Tomcat keine enthält. Wenn Sie Maven verwenden, fügen Sie dies dem dependenciesAbschnitt hinzu:

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

Fügen Sie dann einfach eine Anwendungskonfigurationsklasse zu Ihrem Projekt hinzu. Wenn Sie außer dem Festlegen des Kontextpfads für die restlichen Dienste keine speziellen Konfigurationsanforderungen haben, kann die Klasse leer sein. Sobald diese Klasse hinzugefügt wurde, müssen Sie nichts mehr konfigurieren web.xml(oder überhaupt eine haben):

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 {}

Danach können Sie Ihre Webdienste mithilfe der Standard-JAX-RS-Anmerkungen in Ihren Java-Klassen einfach deklarieren:

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

Dies sollte alles sein, was Sie brauchen. Wenn Ihre Tomcat-Installation lokal auf Port 8080 ausgeführt wird und Sie Ihre WAR-Datei im Kontext bereitstellen myContext, gehen Sie zu ...

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

... sollte das erwartete Ergebnis liefern (5).

Alvin Thompson
quelle
6
@JavaDude - Sie müssen Maven so konfigurieren, dass die WAR-Datei erstellt wird, auch wenn die web.xmlnicht vorhanden ist. Fügen Sie in Ihrem pom.xmlunter "build> plugins" hinzu (falls nicht bereits vorhanden) : <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 - der wichtige Teil ist die <failOnMissingWebXml>false</fai‌​lOnMissingWebXml>Option.
Alvin Thompson
3
@JavaDude - Wenn dies nicht der Fall ist, haben Sie wahrscheinlich keine Klasse erstellt, Applicationdie die @ApplicationPathAnnotation erweitert und hinzufügt . Die Klasse kann leer sein, muss aber vorhanden sein.
Alvin Thompson
3
Es reicht aus, nur hinzuzufügen jersey-container-servlet, ohne die gesamte jaxrs-riAbhängigkeit zu ziehen. ZB in meinem Fall war es 'org.glassfish.jersey.core:jersey-server:2.18'+ 'org.glassfish.jersey.containers:jersey-container-servlet:2.18'.
Leveluptor
3
Da die Frage eindeutig mit "java-ee" gekennzeichnet ist, verstehe ich nicht, wie wichtig es ist, eine Antwort bereitzustellen und zu bewerten, die sich NICHT mit einer Jee-Umgebung befasst. -1
Jan Galinski
51

Es scheint, dass alles, was ich tun musste, dies ist (Servlet 3.0 und höher)

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

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

Und anscheinend war keine web.xml-Konfiguration erforderlich (auf Tomcat 7 ausprobiert)

Eran Medan
quelle
1
Sie verstehen nicht, wie dies funktioniert, Sie können nur die Anmerkung ohne andere Konfiguration verwenden? Ich habe es so versucht und arbeite immer noch nicht ...
Filipe
2
@Filipe: Ich vermute, dass Sie Tomcat oder einen anderen Servlet-Container verwenden. Dies funktioniert bei Servlet-Containern wie Tomcat nicht - es funktioniert nur bei App-Servern wie Glassfish oder Wildfly und möglicherweise bei TomEE. Wenn Sie Tomcat verwenden, lesen Sie meine (späte) Antwort unten.
Alvin Thompson
8
Diese Antwort funktioniert NICHT für Tomcat oder Jetty! Bitte lesen Sie meine Antwort, um die Dinge in diesen (und anderen) Servlet-Containern zum Laufen zu bringen.
Alvin Thompson
1
Je nach Implementierung, Sie tun müssen eine web.xml, obwohl eine leere genügt. Siehe docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/…
Benjamin Maurer
Dies funktioniert unter WebSphere Liberty, jedoch nicht unter WebSphere 8.x und 9.0 Classic.
Archimedes Trajano
15

Kapitel 2 der Spezifikation JAX-RS: Java ™ API für RESTful Web Services beschreibt den Veröffentlichungsprozess einer JAX-RS-Anwendung in einer Servlet-Umgebung (Abschnitt 2.3.2 Servlet in der Spezifikation).

Bitte beachten Sie, dass die Servlet 3-Umgebung nur empfohlen wird (Abschnitt 2.3.2 Servlet, Seite 6):

Es wird EMPFOHLEN, dass Implementierungen den Plug-in-Mechanismus des Servlet 3-Frameworks unterstützen, um die Portabilität zwischen Containern zu ermöglichen und die von Containern bereitgestellten Klassen-Scan-Funktionen zu nutzen.

Kurz gesagt, wenn Sie einen nicht-web.xml Ansatz verwenden wollen, ist es möglich , mit einer benutzerdefinierten Implementierung von javax.ws.rs.core.Application , dass die Registern RESTful Service - Ressourcen mit der javax.ws.rs.ApplicationPath Anmerkung.

@ApplicationPath("/rest")

Obwohl Sie speziell nach Jersey gefragt haben, möchten Sie vielleicht auch den Artikel Implementieren von RESTful-Diensten mit JAX-RS und WebSphere 8.5 Liberty Profile lesen, in dem ich den Veröffentlichungsprozess no-web.xml für WebSphere Liberty Profile (mit Apache Wink als Implementierung von) beschrieben habe JAX-RS).

Jacek Laskowski
quelle
1
Vielen Dank! Ich habe eine andere stark verwandte Frage, die mich verrückt macht. Gibt es eine Möglichkeit, den Pfad im Stammverzeichnis zu haben (z. B. @ApplicationPath ("/ *")) und JSP weiterhin nur mit Anmerkungen zu bedienen? (obwohl ich es selbst mit der Konfiguration von web.xml nicht schaffen konnte) - Frage ist hier: stackoverflow.com/questions/10874188/… , da Sie JAX-RS ziemlich gut zu kennen scheinen, würden Sie bitte einen Blick darauf werfen? :) Vielleicht wirst du sehen, was mir fehlt ... danke!
Eran Medan
Ich weiß es nicht. Bauchgefühle sagen mir, dass es ohne zusätzliche Konfiguration funktionieren sollte, da der Prozess des Auflösens einer Ressource zur Bearbeitung einer Anfrage von der genauen Übereinstimmung mit URL-Mustern abhängt. Ich werde einen Blick darauf werfen und antworten. Vielen Dank, dass Sie mich ermutigt haben, mein Wissen zu erweitern! :-)
Jacek Laskowski
@ApplicationPath("")Ich verwende , um meine REST-Services im Stammverzeichnis (relativ zum Webapp-Kontextstammverzeichnis) auf JBoss EAP 7 zu haben . Ich habe weder beans.xmlnoch web.xml.
Julien Kronegg
7

Sie müssen die richtigen Abhängigkeiten in pom.xml einrichten

<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>

Weitere Details hier: Starterbeispiel für jax-rs

ACV
quelle
Kann ich web.xml löschen, wenn ResourceConfig / Application verwendet wird?
BAE
Ja, aber Sie müssen dies in pom.xml hinzufügen. Ich fusnig mave:<failOnMissingWebXml>
ACV
Vielen Dank. Aber kann web.xml etwas tun, ResourceConfig jedoch nicht?
BAE
Nein, ich denke, da die Servlet-Spezifikation 3.0 web.xml nicht mehr benötigt wird. Manchmal ist es jedoch bequemer, web.xml zu verwenden, da keine Neukompilierung erforderlich ist, wenn Sie etwas ändern möchten.
ACV
Und was ist, wenn Sie Maven nicht verwenden ? Mein Projekt ist momentan zu groß, um zurückzuschalten.
TheRealChx101
1

Die zuvor genannten Abhängigkeiten haben bei mir nicht funktioniert. Aus dem Jersey-Benutzerhandbuch:

Jersey bietet zwei Servlet-Module. Das erste Modul ist das Jersey-Core-Servlet-Modul, das die Kernunterstützung für die Servlet-Integration bietet und in jedem Servlet 2.5- oder höheren Container erforderlich ist:

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

Zur Unterstützung zusätzlicher Servlet 3.x-Bereitstellungsmodi und des asynchronen JAX-RS-Ressourcenprogrammiermodells ist ein zusätzliches Jersey-Modul erforderlich:

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

Das Jersey-Container-Servlet-Modul hängt vom Jersey-Container-Servlet-Core-Modul ab. Daher ist es bei Verwendung nicht erforderlich, die Jersey-Container-Servlet-Core-Abhängigkeit explizit zu deklarieren.

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

bzak
quelle
0

Wie @ Eran-Medan betonte, musste ich bei JBoss EAP 7.1 (Hinweis ohne Webanwendung, also kein Servlet, ich habe es in einem EJB 3.2-Projekt ausgeführt) das Attribut "value" als solches hinzufügen, da ich eine Ausnahme erhielt, dass das Wertattribut war erforderlich.

Das hat bei mir funktioniert

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

            private Set singletons = new HashSet();

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

            ...
    }

Stapelverfolgung

    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
quelle