9

This is what I'm thinking about doing on a JEE Glassfish server using Jersey.

@GET
@Path("/{name}/{date}")
public String getMessages(@PathParam("name") String name, @PathParam("date") Date date)

I like the idea of being able to tell people consuming this RESTful webservice that "The date here is anything that works with the Date class in Java". That's pretty simple from the standpoint that they can just look at the Date spec, and they'll already have a working model that they can test with.

The problem that I'm worried about is that when I do this, JAX-RS is not very nice when Date() doesn't like what it gets in the constructor. Since Date() throws an error if it can't parse what it's given (like if you pass it the string "today" instead of a real date), the JEE server returns a 404 error.

Is this a good practice? Is there a better way to do this that I'm not thinking of?

8

Sounds like a bad idea. For one thing, the Date constructor that you'd be relying on has been deprecated since Java 1.1 in favor of DateFormat.parseDate(), precisely because it's unclear how strings should be parsed into dates, as the rules are different for different localities.

My recommendation would be to stick with a specific format, preferably the internationally understood yyyy-MM-dd, and use a DateFormat to parse the date from a string inside your service, which makes it clear how to consume the web service, and allows you to follow whatever the standard convention for returning error messages is for your web services when something goes wrong.

11

I'm using a custom class DateParam:

@GET
@Path("/{name}/{date}")
public String getMessages(@PathParam("name") String name, @PathParam("date") DateParam date)
  Date date = date.getDate();

The class is defined as:

public class DateParam {
  private final Date date;

  public DateParam(String dateStr) throws WebApplicationException {
    if (isEmpty(dateStr)) {
      this.date = null;
      return;
    }
    final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    try {
      this.date = dateFormat.parse(dateStr);
    } catch (ParseException e) {
      throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
        .entity("Couldn't parse date string: " + e.getMessage())
        .build());
    }
  }

  public Date getDate() {
    return date;
  }
}

If the parameter is empty then you would get a null date. You can extend DateParam by a public static final field for undefined date values. This would make testing for undefined date params clearer.

One drawback here is that for each DateParam, a new instance of SimpleDateFormat is created. However, since SimpleDateFormat is not thread-safe, we cannot reuse it easily.

2

Who will use your service? Will they bother to lookup the specification of the Date class and figure out what kind of strings it will parse? I wouldn't, even if being a Java programmer I would know where to look ;-)

I think you should first tell your users what your URIs will look like, e.g.

.../your-resource-name/yyyy-MM-dd

and then look for a way to have Jersey help you in parsing whatever date format you chose. That could mean using a Date parameter type and maybe specifying a regular expression in your @Path annotation, like

@Path(/{name}/{date: [0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]/)

or using some other class capable of parsing a date in your format. How to handle URIs that don't match the spec you give to your users is yet another thing you should decide how to handle independently of any of the above (return a default resource? return a 404 error?).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.