webentwicklung-frage-antwort-db.com.de

CXF JAXRS - Wie übergebe ich Datum als QueryParam

Ich habe einen Dienst wie folgt definiert.

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

Ich versuche, einen Java.util.Date von meinem Client an ihn zu übergeben (das ist jaxrs: client von CXF, kein generischer HTTP-Client oder Browser).

Mein Dienst erhält das Datum als Thu Mar 01 22:33:10 IST 2012 in der HTTP-URL. Da CXF mit dieser Zeichenfolge kein Date-Objekt erstellen kann, wird auf meinem Client ein 404-Fehler angezeigt. Ich habe versucht, eine ParameterHandler auf der Serviceseite zu verwenden, kann sie jedoch immer noch nicht erfolgreich analysieren, da ich kein Datum in einem bestimmten Format erwarte.

Laut diesem Post soll das Übergeben einer Date sofort funktionieren, aber ich kann den grundlegenden Fall nicht zum Laufen bringen. Muss ich etwas tun, um ein Date-Objekt von meinem Client erfolgreich an service zu übergeben? Schätzen Sie jede Hilfe.

Vielen Dank

41
domino

Das Problem ist, dass JAX-RS die Entbündelung der Parameter auf zwei Arten vorschreibt:

  1. Die Parameter-Bean verfügt über einen öffentlichen Konstruktor, der einen String akzeptiert
  2. Die Parameter-Bean hat eine statische valueOf(String)-Methode.

In Ihrem Fall wird das Datum über seinen Date(String)-Konstruktor entbündelt, der das von Ihrem Client gesendete Eingabeformat nicht verarbeiten kann. Sie haben mehrere Möglichkeiten, um Abhilfe zu schaffen:


Option 1

Bitten Sie Ihren Kunden, das Format des Datums vor dem Senden zu ändern. Dies ist das Ideal, aber wahrscheinlich das Schwierigste!


Option 2 

Behandeln Sie das verrückte Datumsformat. Die Optionen dafür sind:

Ändern Sie Ihre Methodensignatur, um eine Zeichenfolge zu akzeptieren. Versuchen Sie, daraus ein Date-Objekt zu konstruieren. Wenn dies fehlschlägt, verwenden Sie Ihre eigene benutzerdefinierte SimpleDateFormat-Klasse, um es zu analysieren.

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

Definiere deine eigene Parameterklasse, die die oben erwähnte Logik ausführt. Geben Sie ihm einen String-Konstruktor oder eine statische valueOf(String)-Methode, die die Logik aufruft. Und eine zusätzliche Methode, um das Datum zu erhalten, wenn alles gesagt und getan ist.

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

Oder Sie können einen Parameter-Handler für Datumsangaben registrieren. Wo seine Logik einfach die gleiche ist wie für die anderen oben genannten Optionen. Beachten Sie, dass Sie mindestens CXF 2.5.3 verwenden müssen, damit Ihr Parameter-Handler ausgewertet wird, bevor die standardmäßige Entflechtungslogik verwendet wird.

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

Percepitons Antwort war sehr nützlich, aber ParameterHandler wurde in Apache-cxf 3.0 nicht mehr unterstützt, siehe Apache-cxf 3.0-Migrationshandbuch :

CXF JAX-RS ParameterHandler wurde gelöscht, verwenden Sie bitte den JAX-RS 2.0 ParamConverterProvider.

Also füge ich ein Beispiel mit der ParamConverterProvider hinzu:

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

}

Der @SuppressWarnings ist erforderlich, um eine Warnung "Ungeprüfte oder unsichere Operationen" während des Kompilierens zu unterdrücken. Weitere Informationen finden Sie unter Wie kann ich ungeprüfte Cast-Warnungen ansprechen .

Die ParamConverterProvider kann als Provider registriert werden. So habe ich es gemacht:

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

Weitere Informationen finden Sie unter Apache-cxf JAX-RS: Dienstekonfiguration .

10
Christophe Weis

Die Verwendung einer benutzerdefinierten DateParam-Klasse scheint die sicherste Option zu sein. Sie können dann Ihre Methodensignaturen darauf aufbauen und die hässliche Konvertierungslogik in der Methode valueOf () oder dem Klassenkonstruktor implementieren. Es ist auch selbstdokumentierender als die Verwendung von einfachen Zeichenketten

1
Cristian Botiza

Wie @Perception in Option zwei vorschlägt, können Sie das Datum behandeln. Sie sollten jedoch Folgendes verwenden:

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

Sie nennen es aus der Ressource heraus als

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