Question

J'apprends JAX-RS (alias, JSR-311) à l'aide de Jersey. Je l'ai créé avec succès une ressource racine et je jouais avec des paramètres:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

Cela fonctionne très bien, et gère tous les formats dans la configuration locale qui est compris par la date constructeur (String) (comme AAAA / mm / jj mm et / jj / AAAA). Mais si je fournir une valeur qui est invalide ou non compris, je reçois une réponse 404.

Par exemple:

GET /hello?name=Mark&birthDate=X

404 Not Found

Comment puis-je personnaliser ce comportement? Peut-être un code de réponse différent (probablement "400 Bad Request")? Qu'en est-il connecter une erreur? Peut-être ajouter une description du problème ( « mauvais format de date ») dans un en-tête personnalisé pour faciliter le dépannage? Ou revenir ensemble la réponse d'erreur avec des détails, avec un code d'état 5xx?

Était-ce utile?

La solution

Il existe plusieurs approches pour personnaliser le comportement de gestion des erreurs avec JAX-RS. Voici trois des moyens plus faciles.

La première approche est de créer une classe d'exception qui s'étend WebApplicationException.

Exemple:

public class NotAuthorizedException extends WebApplicationException {
     public NotAuthorizedException(String message) {
         super(Response.status(Response.Status.UNAUTHORIZED)
             .entity(message).type(MediaType.TEXT_PLAIN).build());
     }
}

Et pour lancer cette nouvelle exception créer vous simplement:

@Path("accounts/{accountId}/")
    public Item getItem(@PathParam("accountId") String accountId) {
       // An unauthorized user tries to enter
       throw new NotAuthorizedException("You Don't Have Permission");
}

Remarquez, vous n'êtes pas obligé de déclarer l'exception dans une clause throws parce WebApplicationException est une exception d'exécution. Ceci renverra une réponse 401 au client.

La deuxième approche plus facile est de construire simplement une instance du WebApplicationException directement dans votre code. Cette approche fonctionne aussi longtemps que vous n'avez pas à mettre en œuvre vos propres exceptions d'application.

Exemple:

@Path("accounts/{accountId}/")
public Item getItem(@PathParam("accountId") String accountId) {
   // An unauthorized user tries to enter
   throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

Ce code renvoie aussi un 401 au client.

Bien sûr, cela est juste un exemple simple. Vous pouvez faire l'exception beaucoup plus complexe si nécessaire, et vous pouvez générer ce code de réponse http jamais vous avez besoin.

Une autre approche consiste à envelopper une exception existante, peut-être un ObjectNotFoundException avec une petite classe wrapper qui implémente l'interface ExceptionMapper annotée avec une annotation @Provider. Cela indique à l'exécution JAX-RS, que si l'exception est soulevée enveloppé, retournez le code de réponse défini dans le ExceptionMapper.

Autres conseils

@Provider
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException exception){

    return Response.status(Response.Status.NOT_FOUND).
    entity(new ErrorResponse(exception.getClass().toString(),
                exception.getMessage()) ).
    build();
}
}

Créer ci-dessus classe. Cela va gérer 404 (NotFoundException) et ici dans la méthode toResponse vous pouvez donner votre réponse personnalisée. De même, il y a ParamException etc que vous devrez la carte pour fournir des réponses personnalisées.

Jersey jette un com.sun.jersey.api.ParamException quand il ne parvient pas à unmarshall les paramètres pour une solution consiste à créer un ExceptionMapper qui gère ces types d'exceptions:

@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
    @Override
    public Response toResponse(ParamException exception) {
        return Response.status(Status.BAD_REQUEST).entity(exception.getParameterName() + " incorrect type").build();
    }
}

Vous pouvez aussi écrire une classe réutilisable pour les variables QueryParam-annotés

public class DateParam {
  private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

  private Calendar date;

  public DateParam(String in) throws WebApplicationException {
    try {
      date = Calendar.getInstance();
      date.setTime(format.parse(in));
    }
    catch (ParseException exception) {
      throw new WebApplicationException(400);
    }
  }
  public Calendar getDate() {
    return date;
  }
  public String format() {
    return format.format(value.getTime());
  }
}

utilisez comme ceci:

private @QueryParam("from") DateParam startDateParam;
private @QueryParam("to") DateParam endDateParam;
// ...
startDateParam.getDate();

Bien que la gestion des erreurs est trivial dans ce cas (jetant une réponse 400), en utilisant cette classe vous permet de la gestion des paramètres facteur en général qui pourrait inclure l'exploitation forestière, etc.

Une solution évidente: prendre dans une chaîne, vous convertir à jour. De cette façon, vous pouvez définir le format que vous voulez, des exceptions de capture et soit re-lancer ou personnaliser erreur envoyé. Pour l'analyse syntaxique, SimpleDateFormat devrait fonctionner correctement.

Je suis sûr qu'il existe des moyens pour accrocher les gestionnaires aussi pour les types de données, mais peut-être peu de code simple est tout ce dont vous avez besoin dans ce cas.

Moi aussi comme StaxMan serait mettre en œuvre probablement que QueryParam comme une chaîne, puis gérer la conversion, rethrowing si nécessaire.

Si les paramètres régionaux comportement spécifique est le comportement souhaité et attendu, vous pouvez utiliser ce qui suit pour renvoyer le 400 BAD erreur DEMANDE:

throw new WebApplicationException(Response.Status.BAD_REQUEST);

Voir la JavaDoc javax.ws.rs.core.Response.Status pour plus d'options.

documentation @QueryParam dit

  

» Le type T du paramètre annoté, champ ou une propriété doit   soit:

     

1) un type primitif
  2) Avoir un constructeur qui accepte un seul   Argument de chaîne
  3) Avoir une méthode statique nommée valueOf ou fromString   qui accepte un seul argument de chaîne (voir, par exemple,   Integer.valueOf (String))
  4) Avoir une mise en œuvre enregistrée de   javax.ws.rs.ext.ParamConverterProvider JAX-RS prolongement SPI que   renvoie une instance javax.ws.rs.ext.ParamConverter capable d'un « de   chaîne » conversion pour le type.
  5) Soyez Liste, Set ou   SortedSet, où T satisfait 2, 3 ou 4 ci-dessus. La résultante   collection est en lecture seule. «

Si vous voulez contrôler quelle réponse va à l'utilisateur lorsque le paramètre de requête sous forme chaîne ne peut pas être converti en votre type T, vous pouvez jeter WebApplicationException. Dropwizard est livré avec * suivant les classes PARAM pouvez utiliser pour vos besoins.

BooleanParam, DateTimeParam, intParam, LongParam, LocalDateParam, NonEmptyStringParam, UUIDParam. Voir https: // github.com/dropwizard/dropwizard/tree/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/params

Si vous avez besoin Joda DateTime, il suffit d'utiliser Dropwizard DateTimeParam .

Si la liste ci-dessus ne répond pas à vos besoins, définir votre propre en élargissant AbstractParam. Ignorer la méthode analyse. Si vous avez besoin de contrôler sur le corps de réponse d'erreur, méthode d'erreur de remplacement.

Bon article de Coda Hale sur ce point est à http: // codahale. com / what-paramètre-fait-jersey intéressant les classes /

import io.dropwizard.jersey.params.AbstractParam;

import java.util.Date;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

public class DateParam extends AbstractParam<Date> {

    public DateParam(String input) {
        super(input);
    }

    @Override
    protected Date parse(String input) throws Exception {
        return new Date(input);
    }

    @Override
    protected Response error(String input, Exception e) {
        // customize response body if you like here by specifying entity
        return Response.status(Status.BAD_REQUEST).build();
    }
}

Date (String arg) constructeur est dépréciée. J'utilise des classes de date Java 8 si vous êtes sur Java 8. Sinon, le temps de la date de Joda est recommandée.

Ceci est le comportement correct en fait. Jersey va essayer de trouver un gestionnaire pour votre entrée et essayer de construire un objet à partir de l'entrée fournie. Dans ce cas, il va essayer de créer un nouvel objet Date avec la valeur X fournie au constructeur. Étant donné que c'est une date non valide, par convention Jersey retournera 404.

Qu'est-ce que vous pouvez faire est de réécrire et de mettre la date de naissance en tant que chaîne, essayez d'analyser et si vous ne recevez pas ce que vous voulez, vous êtes libre de jeter une exception que vous voulez par l'un des mécanismes de cartographie des exceptions ( il y a plusieurs).

Tout comme une extension @Steven Lavine réponse au cas où vous voulez ouvrir la fenêtre de connexion du navigateur. Je l'ai trouvé difficile de retourner correctement la réponse ( authentification HTTP MDN ) à partir du filtre dans le cas où l'utilisateur n'a pas encore été authentifiée

Cela m'a aidé à construire la réponse à la force connexion du navigateur, notez la modification supplémentaire des en-têtes. Cela définira le code d'état 401 et définir l'en-tête qui provoque le navigateur pour ouvrir la boîte de dialogue nom d'utilisateur / mot de passe.

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top