web-dev-qa-db-fra.com

CXF JAXRS - Comment passer la date en tant que QueryParam

J'ai un service défini comme suit.

public String getData(@QueryParam("date") Date date)

J'essaie de lui passer un Java.util.Date de mon client (qui est jaxrs: client de CXF, pas un client HTTP générique ni un navigateur).

Mon service reçoit la date sous la forme Thu Mar 01 22:33:10 IST 2012 dans l'URL HTTP. CXF ne pouvant pas créer d'objet Date à l'aide de cette chaîne, mon client reçoit une erreur 404. J'ai essayé d'utiliser une ParameterHandler du côté du service, mais je ne parviens toujours pas à l'analyser car je n'attends pas la date dans un format spécifique.

Selon cet article , passer une Date est supposé fonctionner immédiatement, mais je n'arrive pas à faire en sorte que le cas de base fonctionne. Dois-je faire quelque chose pour passer avec succès un objet Date de mon client au service? Appréciez toute aide.

Merci

41
domino

Le problème est que JAX-RS impose que le dégroupage des paramètres soit effectué de l’une des manières suivantes:

  1. Le paramètre bean a un constructeur public qui accepte une chaîne
  2. Le paramètre bean a une méthode statique valueOf(String).

Dans votre cas, la date est dissociée via son constructeur Date(String), qui ne peut pas gérer le format d'entrée envoyé par votre client. Vous avez plusieurs options disponibles pour remédier à cela:


Option 1

Demandez à votre client de changer le format de la date avant de l’envoyer. C'est l'idéal, mais probablement le plus difficile à réaliser!


Option 2 

Gérer le format de date fou. Les options pour cela sont:

Modifiez la signature de votre méthode pour accepter une chaîne. Essayez de construire un objet Date en dehors de cela et si cela échoue, utilisez votre propre classe SimpleDateFormat personnalisée pour l’analyser.

static final DateFormat CRAZY_FORMAT = new SimpleDateFormat("");

public String getData(@QueryParam("date") String dateString) {
    final Date date;
    try {
        date = new Date(dateString); // yes, I know this is a deprecated method
    } catch(Exception e) {
        date = CRAZY_FORMAT.parse(dateString);
    }
}

Définissez votre propre classe de paramètres qui effectue la logique mentionnée ci-dessus. Donnez-lui un constructeur de chaîne ou une méthode statique valueOf(String) qui appelle la logique. Et une méthode supplémentaire pour obtenir la date où tout est dit et fait.

public class DateParameter implements Serializable {
    public static DateParameter valueOf(String dateString) {
        try {
            date = new Date(dateString); // yes, I know this is a deprecated method
        } catch(Exception e) {
            date = CRAZY_FORMAT.parse(dateString);
        }
    }

    private Date date;
    // Constructor, Getters, Setters
}

public String getData(@QueryParam("date") DateParameter dateParam) {
    final Date date = dateParam.getDate();
}

Ou enfin, vous pouvez enregistrer un gestionnaire de paramètres pour les dates. Où sa logique est simplement la même que celle mentionnée pour les autres options ci-dessus. Notez que vous devez utiliser au moins CXF 2.5.3 pour que votre gestionnaire de paramètres soit évalué avant d'essayer la logique de dégroupage par défaut.

public class DateHandler implements ParameterHandler<Date> {
    public Map fromString(String s) {
        final Date date;
        try {
            date = new Date(dateString); // yes, I know this is a deprecated method
        } catch(Exception e) {
            date = CRAZY_FORMAT.parse(dateString);
        }
    }
}
55
Perception

La réponse de Percepiton était très utile, mais ParameterHandler est obsolète dans Apache-cxf 3.0, voir le Guide de migration Apache-cxf 3.0 :

CXF JAX-RS ParameterHandler a été supprimé. Veuillez utiliser JAX-RS 2.0 ParamConverterProvider.

J'ajoute donc un exemple avec la variable ParamConverterProvider:

public class DateParameterConverterProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> type, Type type1, Annotation[] antns) {
        if (Date.class.equals(type)) {
            @SuppressWarnings("unchecked")
            ParamConverter<T> paramConverter = (ParamConverter<T>) new DateParameterConverter();
            return paramConverter;
        }
        return null;
    }

}

public class DateParameterConverter implements ParamConverter<Date> {

    public static final String format = "yyyy-MM-dd"; // set the format to whatever you need

    @Override
    public Date fromString(String string) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        try {
            return simpleDateFormat.parse(string);
        } catch (ParseException ex) {
            throw new WebApplicationException(ex);
        }
    }

    @Override
    public String toString(Date t) {
        return new SimpleDateFormat(format).format(t);
    }

}

Le @SuppressWarnings est requis pour supprimer un avertissement "opérations non contrôlées ou non sécurisées" lors de la compilation. Voir Comment puis-je traiter les avertissements de distribution non vérifiés pour plus de détails.

La ParamConverterProvider peut être enregistrée en tant que fournisseur. Voici comment je l'ai fait:

  <jaxrs:server id="myService" address="/rest">
      <jaxrs:serviceBeans>
           ...
      </jaxrs:serviceBeans>

      <jaxrs:providers>
          <ref bean="dateParameterConverterProvider" />
      </jaxrs:providers>
  </jaxrs:server>

  <bean id="dateParameterConverterProvider" class="myPackage.DateParameterConverterProvider"/>

Voir Apache-cxf JAX-RS: Configuration des services pour plus d'informations.

10
Christophe Weis

L'utilisation d'une classe DateParam personnalisée semble être l'option la plus sûre. Vous pouvez ensuite baser vos signatures de méthodes sur cette dernière et implémenter la logique de conversion laide dans la méthode valueOf () ou le constructeur de la classe. C'est aussi plus auto-documenté que d'utiliser des chaînes simples

1
Cristian Botiza

Comme le suggère @Perception dans l'option deux, vous pouvez gérer la date. Mais vous devriez utiliser ce qui suit:

private Date getDateFromString(String dateString) {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        Date date = df.parse(dateString);
        return date;
    } catch (ParseException e) {
        //WebApplicationException ...("Date format should be yyyy-MM-dd'T'HH:mm:ss", Status.BAD_REQUEST);
    }
}

Vous l'appelez depuis la ressource en tant que

Date date = getDateFromString(dateString);//dateString is query param.
0
kasavbere