web-dev-qa-db-fra.com

Comment configurer l'application JAX-RS en utilisant uniquement des annotations (pas de fichier web.xml)?

Est-il possible de configurer une application JAX-RS en utilisant uniquement des annotations? (utilisant Servlet 3.0 et JAX-RS Jersey 1.1.0)

J'ai essayé et n'ai pas eu de chance. L'utilisation de web.xml Semble nécessaire.


Configuration A (fonctionne, mais a la configuration 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 {
    ...
}

Configuration B (ne fonctionne pas, exception levée)

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

Ce dernier semble insister sur le fait que l'application sera une sous-classe de Servlet (l'exception ne laisse rien deviner)

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

Questions

  1. Pourquoi la définition web.xml a fonctionné alors que l'annotation n'a pas fonctionné? Quelle est la différence?

  2. Y a-t-il un moyen de le faire fonctionner, par exemple avez une application JAX-RS sans web.xml?

76
Eran Medan

Il semble que tout ce que j'avais à faire était le suivant (Servlet 3.0 et versions ultérieures)

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

Et aucune configuration web.xml n'était apparemment nécessaire (essayé sur Tomcat 7)

48
Eran Medan

** S'IL VOUS PLAÎT LIRE SI VOUS UTILISEZ Tomcat OR JETTY! **)

La réponse acceptée fonctionne fonctionne, mais uniquement si l'application Web est déployée sur un serveur d'applications tel que Glassfish ou Wildfly, et éventuellement des conteneurs de servlets avec des extensions EE telles que TomEE. Cela ne fonctionne pas fonctionne sur des conteneurs de servlets standard tels que Tomcat, que la plupart des personnes à la recherche d’une solution ici voudront utiliser.

Si vous utilisez une installation Tomcat standard (ou un autre conteneur de servlet), vous devez inclure une implémentation REST car Tomcat n’en fournit pas d’application. Si vous utilisez Maven, ajoutez ceci à la section dependencies:

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

Ensuite, ajoutez simplement une classe de configuration d'application à votre projet. Si vous n'avez pas de configuration particulière à part définir le chemin de contexte pour les services restants, la classe peut être vide. Une fois cette classe ajoutée, vous n'avez rien besoin de configurer dans web.xml (ou en avoir un du tout):

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

Ensuite, vous déclarez directement vos services Web en utilisant les annotations JAX-RS standard dans vos classes 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);
  }
}

Cela devrait être tout ce dont vous avez besoin. Si votre installation Tomcat s'exécute localement sur le port 8080 et que vous déployez votre fichier WAR dans le contexte myContext, accédez à ...

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

... devrait produire le résultat attendu (5).

158
Alvin Thompson

Le chapitre 2 de la spécification JAX-RS: API Java ™ pour services Web RESTful décrit le processus de publication d’une application JAX-RS dans l’environnement Servlet (section 2.3.2 Servlet = = dans la spécification).

Veuillez noter que l'environnement Servlet 3 est uniquement recommandé (section 2.3.2 Servlet, page 6):

Il est RECOMMANDÉ que les implémentations prennent en charge le mécanisme de connectivité de l’infrastructure Servlet 3 afin de permettre la portabilité entre les conteneurs et d’utiliser les fonctions d’analyse de classe fournies par les conteneurs.

En bref, si vous souhaitez utiliser une approche no-web.xml, il est possible avec une implémentation personnalisée de javax.ws.rs.core.Application qui enregistre les ressources de service RESTful avec le javax.ws.rs.ApplicationPath annotation.

@ApplicationPath("/rest")

Bien que vous ayez demandé spécifiquement à propos de Jersey, vous aimerez peut-être aussi lire l'article Implémentation de services RESTful avec JAX-RS et le profil WebSphere 8.5 Liberty dans lequel j'ai décrit le processus de publication no-web.xml pour WebSphere Liberty Profile (avec Apache Wink comme implémentation de JAX-RS).

14
Jacek Laskowski

Vous devez configurer les bonnes dépendances dans 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>

Plus de détails ici: Exemple de démarrage pour jax-rs

6
ACV

Les dépendances mentionnées précédemment ne fonctionnaient pas pour moi. Du guide de l'utilisateur Jersey:

Jersey fournit deux modules Servlet. Le premier module est le module Servlet principal de Jersey, qui fournit le support d'intégration principal des servlets. Il est requis dans tout conteneur Servlet 2.5 ou supérieur:

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

Pour prendre en charge des modes de déploiement Servlet 3.x supplémentaires et un modèle de programmation de ressources JAX-RS asynchrone, un module Jersey supplémentaire est requis:

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

Le module jersey-container-servlet dépend du module jersey-container-servlet-core. Par conséquent, lorsqu'il est utilisé, il n'est pas nécessaire de déclarer explicitement la dépendance jersey-container-servlet-core.

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

0
bzak

Comme @ Eran-Medan l'a fait remarquer, JBoss EAP 7.1 (remarque sans application Web, donc pas de servlet, je le faisais dans un projet EJB 3.2). J'ai dû ajouter l'attribut "value" en tant que tel, l'attribut value était requis.

Cela a fonctionné pour moi

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

            private Set singletons = new HashSet();

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

            ...
    }

trace de pile

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