dimanche 19 octobre 2014

JAX-RS Clients : Les différentes solutions d’un client Web Service Rest


REST (REpresentational State Transfer) : le style architectural du Web
REST (ou RESTful, l’adjectif qui qualifie une architecture de type REST) n’est pas une technologie, ni un protocole ou un standard. C’est plutôt un style architectural : notion proposée par Roy Fielding (l’un des créateurs du protocole HTTP) dans sa thèse (2000) : Architectural Styles and the Design of Network-based Software Architectures. Ce style part du principe selon lequel Internet n’est pas un ensemble de pages mais comme un ensemble de ressources accessibles à partir d’une URI (Uniform Resource Identifier). Plus précisément, REST est un ensemble de critères de conception. Une architecture répond plus à ses critères qu’une autre, mais en aucun cas, nous ne pouvons pas dire que REST est une architecture.
Java EE 6 spécifie une API REST nommée JAX-RS. Cette spécification précise ce que peut ou doit faire une implémentation. Elle est la standardisation des services REST en Java et définit un ensemble d'annotations permettant d'exposer des classes java comme service REST. L'intérêt de la standardisation est de ne pas se lier à une implémentation spécifique. Plusieurs implémentations existent : Sun Jersey, Jbosse Resteasy, Spring RestTemplate, Apache Wink, CXF …L’implémentation de référence de cette API est Jersey qui n’est ni plus ni moins qu’une servlet qui prend en charge vos classes java en fonction d’annotations que vous allez utiliser.
JAX-RS spécifie l'implémentation partie serveur et ne propose rien côté client. Les implémentations fournissent généralement une API client permettant d'appeler des services REST respectant le standard JAX-RS.
Nous allons voir dans cet article les différentes solutions pour implémenter un client JAX-RS. Pour chaque client, j’énumère les dépendances maven nécessaires pour son implémentation ainsi qu’un exemple minimum de code source.
Afin de simplifier le code, chaque client implémente une interface commune : NotificationClientService


package com.larbotech.ws.domain.com.larbotech.ws.notification.service;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;

/**
 * Created by mlarbo on 18/10/14.
 */
public interface NotificationClientService {
    public static final String BASE_URL = "http://localhost:9090/larbotech-notification-service";
    public static final String NOTIFICATION_URI = BASE_URL + "/notification/{id}";
    public static final String NOTIFICATION_POST_URI = BASE_URL + "/notification";
    public static final String NOTIFICATIONS_URI = BASE_URL + "/notifications";
    public static final int connectionTimeoutMillis = 2000;
    public static final int socketTimeoutMillis = 3000;

     void deleteNotification(long id);

     Notification addNotification(Notification notification) ;

     Notification getNotification(long id);

     NotificationList getAll();

}
  
Création d'un service Rest
Supposons que nous voulons réaliser un serveur REST pour gérer des notifications d’un système d’information. L’objectif est de pouvoir notifier des événements via un objet notification. Cet objet (notification) représente la ressource. Nous devons donc pouvoir ajouter (POST), modifier (PUT), Lire (GET) et Supprimer (DELETE) des notifications.
Je commence par implémenter un service Rest de notification et le déployer sur un serveur tomcat grâce au plugin tomcat7 de maven. Ce service sera ensuite utilisé par nos différents clients. L’API REST s’appuie sur le principe des ressources. Pour implémenter un service REST, il suffit donc d’implémenter une classe (le controller) qui contient des méthodes capables de traiter requêtes HTTP. Selon le type de méthode HTTP (GET, POST, PUT ou DELETE), la méthode peut prendre un ou plusieurs paramètres de type quelconque ! L’objectif de cet article est de vous montrer comment créer de client mais pas comment créer un service Rest. Nous nous focalisons donc sur le code de clients. 
Voici le code source du Controller de notre service Rest de notification :
package com.larbotech.ws.notification.controller;

import javax.annotation.Resource;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import com.larbotech.ws.notification.service.NotificationWebService;


;

/**
 * REST service provider
 */
@Controller
@RequestMapping("/")
public class NotificationController {
    private static Logger logger = Logger.getLogger(NotificationController.class);

    @Resource(name = "notificationWebService")
    private NotificationWebService notificationWebService;

    @RequestMapping(value = "/notifications",
            method = RequestMethod.GET,
            headers = "Accept=application/xml, application/json")
    @ResponseBody
    public NotificationList getNotifications() {
        logger.debug("Provider has received request to get all notifications");
        // Call service here
        NotificationList result = new NotificationList();
        result.setData(notificationWebService.getNotifications());
        return result;
    }

    @RequestMapping(value = "/notification/{id}",
            method = RequestMethod.GET,
            headers = "Accept=application/xml, application/json")

    @ResponseBody
    public Notification getNotification(@PathVariable("id") Long id) {
        logger.debug("Provider has received request to get notification with id: " + id);

        // Call service here
        return notificationWebService.getNotification(id);
    }

    @RequestMapping(value = "/notification",
            method = RequestMethod.POST,
            headers = "Accept=application/xml, application/json")
    @ResponseBody
    public Notification addNotification(@RequestBody Notification notification) {
        logger.debug("Provider has received request to add new notification");

        // Call service to here
        return notificationWebService.toSaveNotification(notification);
    }

    @RequestMapping(value = "/notification/{id}",
            method = RequestMethod.DELETE,
            headers = "Accept=application/xml, application/json")
    @ResponseBody
    public String deleteNotification(@PathVariable("id") Long id) {
        logger.debug("Provider has received request to delete notification with id: " + id);
        // Call service here
        return String.valueOf(notificationWebService.toDeleteNotification(id));
    }

}

Client Sun Jeresey

Dépendance maven :

     <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>1.18.1</version>
        </dependency>


La classe de configuration du client :


package com.larbotech.ws.notification.client;

import static java.lang.Integer.valueOf;

import com.sun.jersey.api.client.config.DefaultClientConfig;

/**
 * Created by m-toure on 21/08/2014.
 */
public class NotificationClientConfig extends DefaultClientConfig
{

 public NotificationClientConfig()
 {
/*  getProperties().put( PROPERTY_CONNECT_TIMEOUT, valueOf( 2000 ) );// 2 seconds for connection
  getProperties().put( PROPERTY_READ_TIMEOUT, valueOf( 2000 ) );// 2 seconds read timeout*/
       getProperties().put( PROPERTY_CONNECT_TIMEOUT, valueOf( 30000 ) );// 30 seconds for connection
        getProperties().put( PROPERTY_READ_TIMEOUT, valueOf( 30000 ) );// 30 seconds read timeout
 }

}

La classe d'appel au service rest :


package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import com.larbotech.ws.domain.com.larbotech.ws.notification.service.NotificationClientService;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;

/**
 * Created by mlarbo on 18/10/14.
 */
public class SunJereseyClient implements NotificationClientService{
    private static Logger logger = LoggerFactory.getLogger(NotificationClientService.class);

    private final Client clientObject = Client.create( new NotificationClientConfig() );
    private WebResource notificationResource;

    public static void main(String[] args) {
        SunJereseyClient sunJereseyClient = new SunJereseyClient();
        Notification notification = sunJereseyClient.getNotification(4);
        logger.info(notification.toString());
        sunJereseyClient.deleteNotification(4);
        notification = sunJereseyClient.addNotification(notification);
        logger.info(notification.toString());
        NotificationList notificationList = sunJereseyClient.getAll();
        for (Notification notification1:notificationList.getData()){
            logger.info(notification1.toString());
        }
    }
    public WebResource getNotificationResource() {
        if ( notificationResource == null )
        {
            URI uriObject = UriBuilder.fromUri(BASE_URL).build();
            notificationResource = clientObject.resource( uriObject );
        }
        return notificationResource;
    }

    @Override
    public void deleteNotification(long id) {
        WebResource innerResource = getNotificationResource().path( "notification" ).path(String.valueOf(id));
        WebResource.Builder builderObject = innerResource.accept( MediaType.APPLICATION_XML );
         builderObject.delete();
    }

    @Override
    public Notification addNotification(Notification notification) {
        WebResource innerResource = getNotificationResource().path("notification");
        WebResource.Builder builderObject = innerResource.accept( MediaType.APPLICATION_XML );
        return builderObject.post(Notification.class, notification);
    }

    @Override
    public Notification getNotification(long id) {
        WebResource innerResource = getNotificationResource().path( "notification" ).path( String.valueOf( id ) );
        WebResource.Builder builderObject = innerResource.accept( MediaType.APPLICATION_XML );
        return builderObject.get( Notification.class );
    }

    @Override
    public NotificationList getAll() {
        WebResource innerResource = getNotificationResource().path( "notifications" );
        WebResource.Builder builderObject = innerResource.accept( MediaType.APPLICATION_XML );
        return builderObject.get( NotificationList.class );
    }
}

Spring RestTemplate

Dépnedance maven :
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.3.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.5</version>
            <scope>compile</scope>
        </dependency>

La classe du client RestTemplate


package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import com.larbotech.ws.domain.com.larbotech.ws.notification.service.NotificationClientService;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Collections;

/**
 * Created by mlarbo on 17/10/14.
 */
public class SpringClient implements NotificationClientService{
    private static Logger logger = LoggerFactory.getLogger(SpringClient.class);
    private RestTemplate template;

    public static void main(String[] args) {
        SpringClient springClient = new SpringClient();
        Notification notification = springClient.getNotification(4);
        logger.info(notification.toString());
        springClient.deleteNotification(4);
        notification = springClient.addNotification(notification);
        logger.info(notification.toString());
        NotificationList notificationList = springClient.getAll();
        for (Notification notification1:notificationList.getData()){
            logger.info(notification1.toString());
        }
    }
    public SpringClient() {
        ClientHttpRequestFactory requestFactory
                = new HttpComponentsClientHttpRequestFactory(initHttpClient());
        template = new RestTemplate(requestFactory);
        template.setErrorHandler(new ErrorHandler());
    }

    @Override
    public void deleteNotification(long id){
        template.delete(NOTIFICATION_URI, Collections.singletonMap("id", String.valueOf(id)));
    }

    @Override
    public Notification addNotification(Notification notification) {
        return template.postForObject(NOTIFICATION_POST_URI, notification, Notification.class);
    }

    @Override
    public Notification getNotification(long id) {
        return template.getForObject(NOTIFICATION_URI, Notification.class,
                Collections.singletonMap("id", String.valueOf(id)));
    }

    @Override
    public NotificationList getAll() {
        return template.getForObject(NOTIFICATIONS_URI, NotificationList.class);
    }

    private static final class ErrorHandler implements ResponseErrorHandler {
        @Override
        public boolean hasError(ClientHttpResponse response) throws IOException {
            if (response.getStatusCode().series().compareTo(HttpStatus.Series.SUCCESSFUL) == 0) {
                return false;
            }
            return true;
        }

        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            if (response.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
                throw new IOException("Notification Not Found");
            } else if (response.getStatusCode().equals(HttpStatus.BAD_REQUEST)) {
                throw new IOException("Error validating notification");
            } else {
                throw new IOException("Unexpected error:" + response.getStatusText());
            }
        }
    }

    private static HttpClient initHttpClient() {
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectionRequestTimeout(1000).setConnectTimeout(connectionTimeoutMillis).setSocketTimeout(socketTimeoutMillis).build();
        HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig);
        return builder.build();
    }
}

Client Jboss Resteasy :

Dépendance maven :

 <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>2.3.1.GA</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson-provider</artifactId>
        <version>2.3.1.GA</version>
        <exclusions>
            <exclusion>
                <artifactId>jackson-core-asl</artifactId>
                <groupId>org.codehaus.jackson</groupId>
            </exclusion>
            <exclusion>
                <artifactId>jackson-mapper-asl</artifactId>
                <groupId>org.codehaus.jackson</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jettison-provider</artifactId>
        <version>2.3.1.GA</version>
    </dependency>

Des classes utilités pour simplifier le code :

 1) Configuration du client  

package com.larbotech.ws.notification.client;


import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;

/**
 * Created by m-toure on 17/10/2014.
 */
public class ClientExecutor extends ApacheHttpClient4Executor
{

    private static final int connectionTimeoutMillis = 2000;
    private static final int socketTimeoutMillis = 3000;

    public ClientExecutor()
    {
        super( initHttpClient() );
    }

    private static DefaultHttpClient initHttpClient()
    {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpParams params = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, connectionTimeoutMillis);
        HttpConnectionParams.setSoTimeout( params, socketTimeoutMillis );
        return httpClient;
    }
}

2) La classe factoy qui crée de proxy en fonction de l'interface proxy fournie en paramètre généric :


package com.larbotech.ws.notification.client;

import org.jboss.resteasy.client.ProxyFactory;

/**
 * Created by m-toure on 17/10/2014.
 */
public class ClientFactory {

    private ClientExecutor executor = new ClientExecutor();

    public <T> T create( Class<T> clazz, String  baseUri)
    {
        //executor.getHttpClient().getParams().e
        return ProxyFactory.create(clazz, baseUri, executor);
    }
}

3) L'interface proxy avec des annoatation JAX-RS : A ne pas confondre avec l'interface commune aux clients. Cette dernière est facultative; c'est juste pour simplifier le code de clients. Cependant, l'interface proxy est obligatoire pour implémenter un client Jboss Resteasy :

package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;

import javax.ws.rs.*;


/**
 * RESTEasy Client Proxies
 *
 * Created by m-toure on 17/10/2014.
 */
@Consumes(value = "application/xml")
public interface NotificationServiceProxy {

    @GET
    @Path( "/notification/{id}" )
    @Produces( "application/xml")
            //@QueryParam si  c'est du paramètre du type /notification?id=x,v=valeur
    Notification getNotification( @PathParam( "id" ) long id );

    @DELETE
    @Path( "/notification/{id}" )
    @Produces( "application/xml")
    String remove( @PathParam( "id" ) long id );

    @POST
    @Path( "/notification" )
    @Produces("application/xml" )
    Notification addNotification( Notification notification );

    @GET
    @Path( "/notifications" )
    @Produces( "application/xml")
    NotificationList getNotifications();
}

Enfin la classe du client :


package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import com.larbotech.ws.domain.com.larbotech.ws.notification.service.NotificationClientService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by m-toure on 17/10/2014.
 */
public class JbossResteasyClient implements NotificationClientService {

    private static Logger logger = LoggerFactory.getLogger(JbossResteasyClient.class);
    private ClientFactory clientFactory = new ClientFactory();
    //psvm + tab
    public static void main(String[] args) {
        JbossResteasyClient jbossResteasyClient = new JbossResteasyClient();
        Notification notification = jbossResteasyClient.getNotification(4);
        logger.info(notification.toString());
        jbossResteasyClient.deleteNotification(4);
        notification = jbossResteasyClient.addNotification(notification);
        logger.info(notification.toString());
        NotificationList notificationList = jbossResteasyClient.getAll();
        for (Notification notification1:notificationList.getData()){
            logger.info(notification1.toString());
        }
    }


    @Override
    public void deleteNotification(long id) {
        clientFactory.create( NotificationServiceProxy.class,  BASE_URL).remove(id);
    }

    @Override
    public Notification addNotification(Notification notification) {
       return clientFactory.create( NotificationServiceProxy.class,  BASE_URL).addNotification(notification);
    }

    @Override
    public Notification getNotification(long id) {
        return clientFactory.create( NotificationServiceProxy.class,  BASE_URL).getNotification(id);
    }

    @Override
    public NotificationList getAll() {
        return clientFactory.create( NotificationServiceProxy.class,  BASE_URL).getNotifications();
    }
}



CXF client

Dépendance maven :


      <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>2.7.13</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>

Classe du client (on utilise ici la même interface proxy que pour le client Jboss Resteasy)


package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import com.larbotech.ws.domain.com.larbotech.ws.notification.service.NotificationClientService;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by mlarbo on 18/10/14.
 */
public class CXFClient implements NotificationClientService {
    private static Logger logger = LoggerFactory.getLogger(CXFClient.class);


    public static void main(String[] args) {
        CXFClient cxfClient = new CXFClient();
        Notification notification = cxfClient.getNotification(4);
        logger.info(notification.toString());
        cxfClient.deleteNotification(4);
        notification = cxfClient.addNotification(notification);
        logger.info(notification.toString());
        NotificationList notificationList = cxfClient.getAll();
        for (Notification notification1:notificationList.getData()){
            logger.info(notification1.toString());
        }
    }

    @Override
    public void deleteNotification(long id) {
       JAXRSClientFactory.create(BASE_URL, NotificationServiceProxy.class).remove(id);
    }

    @Override
    public Notification addNotification(Notification notification) {
        return JAXRSClientFactory.create(BASE_URL, NotificationServiceProxy.class).addNotification(notification);
    }

    @Override
    public Notification getNotification(long id) {
        return JAXRSClientFactory.create(BASE_URL, NotificationServiceProxy.class).getNotification(id);
    }

    @Override
    public NotificationList getAll() {
        return JAXRSClientFactory.create(BASE_URL, NotificationServiceProxy.class).getNotifications();
    }
}

Apache Wink

Dépendance maven :

 <dependency>
            <groupId>org.apache.wink</groupId>
            <artifactId>wink-client-apache-httpclient</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.3.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.5</version>
            <scope>compile</scope>
        </dependency>

La classe du client :

package com.larbotech.ws.notification.client;

import com.larbotech.ws.domain.Notification;
import com.larbotech.ws.domain.NotificationList;
import com.larbotech.ws.domain.com.larbotech.ws.notification.service.NotificationClientService;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.ClientResponse;
import org.apache.wink.client.RestClient;
import org.apache.wink.client.httpclient.ApacheHttpClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

/**
 * Created by mlarbo on 18/10/14.
 */
public class ApacheWinkClient implements NotificationClientService{
    private static Logger logger = LoggerFactory.getLogger(ApacheWinkClient.class);
    private final RestClient restClient;

    public static void main(String[] args) {
        ApacheWinkClient apacheWinkClient = new ApacheWinkClient();
        Notification notification = apacheWinkClient.getNotification(4);
        logger.info(notification.toString());
        apacheWinkClient.deleteNotification(4);
        notification = apacheWinkClient.addNotification(notification);
        logger.info(notification.toString());
        NotificationList notificationList = apacheWinkClient.getAll();
        for (Notification notification1:notificationList.getData()){
            logger.info(notification1.toString());
        }
    }
    public ApacheWinkClient() {
        ClientConfig config = new ApacheHttpClientConfig(initHttpClient());
        // Exception handler
        //config.handlers(your exception handler);
        restClient = new RestClient(config);
    }

    private static HttpClient initHttpClient() {
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectionRequestTimeout(1000).setConnectTimeout(connectionTimeoutMillis).setSocketTimeout(socketTimeoutMillis).build();
        HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig);
        return builder.build();
    }

    @Override
    public void deleteNotification(long id){
        ClientResponse response = restClient.resource(
                UriBuilder.fromUri(BASE_URL).path("/notification/").path("{id}").build(String.valueOf(id))).accept(
                MediaType.APPLICATION_XML).delete();
          // return response.getEntity(String.class);
         }

    @Override
    public Notification addNotification(Notification notification) {
        return restClient.resource(UriBuilder.fromUri(BASE_URL).path("/notification/").build())
                .contentType(MediaType.APPLICATION_XML).accept(MediaType.APPLICATION_XML).post(
                        Notification.class, notification);
    }

    @Override
    public Notification getNotification(long id) {
        return restClient.resource(
                UriBuilder.fromUri(BASE_URL).path("/notification/").path("{id}").build(String.valueOf(id))).accept(
                MediaType.APPLICATION_XML).get(Notification.class);
    }

    @Override
    public NotificationList getAll() {
        return restClient.resource(
                UriBuilder.fromUri(BASE_URL).path("/notifications/").build()).accept(
                MediaType.APPLICATION_XML).get(NotificationList.class);
    }
}

Erreurs éventuelles :


java.lang.AbstractMethodError: javax.ws.rs.core.UriBuilder.uri(Ljava/lang/String;)Ljavax/ws/rs/core/UriBuilder;
	at javax.ws.rs.core.UriBuilder.fromUri(UriBuilder.java:119)

Il suffit de chercher et d'exclure la lib javax.ws.rs-api (commande mvn dependancy:tree) :

<exclusion>
    <artifactId>javax.ws.rs-api</artifactId>					
    <groupId>javax.ws.rs</groupId>
</exclusion>