Przesyłanie daty w serwisach REST (Jersey)

Error 400 Bad Request… tak potraktował mnie dziś mój rest‚owy serwis, gdy próbowałem przekazać mu parametr z datą. Próby przekazywania daty w różnych formatach na nic się nie zdały, serwis dalej zbywał mnie brzydką odpowiedzią. A wyglądał on mniej więcej tak:

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_XML)
public Response action(@FormParam("date") Date date) {
  ...
}

W rzeczywistości ma jeszcze kilka innych parametrów, ale one przechodziły bez problemu. Co ciekawe, różne źródła w internecie mówią, że „u nich działa”. Szukamy zatem przyczyny problemu.

Czytając JavaDoc’a adnotacji @FormParam dowiadujemy się, że typ przyjmowanego parametru musi spełniać jeden z poniższych warunków:

  1. Być typem prymitywnym.
  2. Posiadać konstruktor z pojedynczym argumentem typu String.
  3. Posiadać statyczną metodę valueOf lub fromString przyjmującą pojedynczy argument typu String.
  4. Być kolekcją typu List, Set lub SortedSet, gdzie elementy kolekcji spełniają 2 lub 3 warunek.

Jak się ma do tego java.util.Date? Ano ma konstruktor przyjmujący Stringa, dodatkowo oznaczony jako @Deprecated z podpowiedzią, że został zastąpiony przez java.text.DateFormat.parse(String s). Pomimo tego z serwisem REST postawionym z wykorzystaniem biblioteki Jersey współpracować nie chce.

Co dalej? Tworzymy własny typ spełniający powyższe warunki. Fajnie by było, gdyby parsował on różne odmiany formatu daty zgodnym z normą ISO 8601.

import java.util.Date;

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

import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

public class ISODate {
  private DateTimeFormatter format = ISODateTimeFormat.dateTimeParser();
  private Date date;

  public ISODate(String source) throws WebApplicationException {
    try {
      date = format.parseDateTime(source).toDate();
    } catch (UnsupportedOperationException e) {
      throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
    } catch (IllegalArgumentException e) {
      throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
    }
  }
  public Date getDate() {
    return date;
  }
}

Wykorzystałem tu znaną zapewne większości bibliotekę joda-time, zapewniającą mniej frustrujące od standardowej biblioteki podejście do manipulacji czasem w Javie.

Modyfikujemy odpowiednio serwis:

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_XML)
public Response action(@FormParam("date") ISODate isoDate) {
  Date date = isoDate.getDate();
  ...
}

I… działa! :)

Skomentuj

4 Komentarze.

  1. A może mi ktoś napisać czego się uczyć po html i css?

  2. look @org.glassfish.jersey.server.internal.inject.ParamConverters.DateProvider

Skomentuj


UWAGA - Możesz używać HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv badge