Working with cookies in JAX-RS

[Updated: Apr 5, 2017, Created: Apr 3, 2017]

This is a quick walk-through of handling cookies in JAX-RS by using @CookieParam, Cookie, NewCookie, HttpHeaders#getCookies and Response. Response Builder# cookie(. . ).

Creating cookies and adding in Response

@Path("/")
public class MyResource {

  @GET
  @Path("test1")
  public Response createCookies() {
      NewCookie cookie1 = new NewCookie("myStrCookie", "cookieStrVal");
      NewCookie cookie2 = new NewCookie("myDateCookie", "2017-03-28");
      NewCookie cookie3 = new NewCookie("myIntCookie", "100");
      Response.ResponseBuilder rb = Response.ok("myStrCookie, "
              + "myDateCookie and myIntCookie sent to the browser");
      Response response = rb.cookie(cookie1, cookie2, cookie3)
                            .build();
      return response;
  }
}

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run

Output

A quick note on cookie specifications

A Response cookie object is sent as 'Set-Cookie' HTTP header. This header consists of various semi-colon separated directives:

Set-Cookie: <name>=<value>;Max-Age=<value>;Path=<value>;version=<value>;Domain=<value>;Comment=<value>;Secure

Multiple cookies can be sent in separate lines of 'Set-Cookie' headers or in a single comma separated line.

A valid cookie name and value cannot have semicolon, comma, and white spaces. No standard exists, for encoding these characters. We must avoid using them for portability and to avoid unexpected results.

A Request cookie object is sent by the browser. It is nothing but 'Cookie' HTTP header. These headers are applied based on previously persisted Domain/Max-Age/Path/Secure attributes. It has the similar syntax as described above.

Accessing all cookies in the request

@Path("/")
public class MyResource {

  @GET
  @Path("test2")
  public String readAllCookies(@Context HttpHeaders headers) {
      Map<String, Cookie> cookies = headers.getCookies();
      String str = cookies.entrySet()
                          .stream()
                          .map(e -> e.getKey() + " = " + e.getValue().getValue())
                          .collect(Collectors.joining("<br/>"));
      return str;
  }
}

@CookieParam Examples

@CookieParam binds the value of a specific cookie to a resource method parameter.

@Path("/")
public class MyResource {

  @GET
  @Path("test3")
  public String readCookie1(@CookieParam("myStrCookie") String strCookie) {
      return "myStrCookie value = " + strCookie;
  }
}

Automatic type binding

Other than String, various other types can be used with @CookieParam. In following examples, We will learn each of them.

Binding to Java primitives

@Path("/")
public class MyResource {

  @GET
  @Path("test4")
  public String readCookie2(@CookieParam("myIntCookie") int intCookie) {
      return "myIntCookie value  = " + intCookie;
  }
}

Binding to Java type which has a String accepting constructor

For example BigDecimal has a String accepting constructor:

@Path("/")
public class MyResource {

  @GET
  @Path("test5")
  public String readCookie3(@CookieParam("myIntCookie") BigDecimal bd) {
      return "myIntCookie value in BigDecimal = " + bd;
  }
}

Similarly, We can use our own object type having a String accepting constructor.

Binding to a type which has a factory method valueOf(String)

@Path("/")
public class MyResource {

  @GET
  @Path("test6")
  public String readCookie4(@CookieParam("myIntCookie") Long aLong) {
      return "myIntCookie  in Long :" + aLong;
  }
}

Using Cookie object

javax.ws.rs.core.Cookie is another type which has valueOf(String) method. But, in this special case, JAX-RS populates not only the cookie value but other cookie attributes too.

@Path("/")
public class MyResource {

  @GET
  @Path("test7")
  public String readCookie5(@CookieParam("myDateCookie") Cookie cookie) {
      return "Cookie object :" + cookie;
  }
}

We can also create our own class having static factory valueOf(String) method.

Binding to type which implements ParamConverter

In this example, we will bind java.time.LocalDate to the cookie value by implementing ParamConverter:

public class MyDateConverter implements ParamConverter<LocalDate> {
  @Override
  public LocalDate fromString(String value) {
      if (value == null || value.trim().isEmpty()) {
          return null;
      }
      return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE);
  }

  @Override
  public String toString(LocalDate value) {
      return value==null? "": value.toString();
  }
}

Registering our custom ParamConverter

@Provider
public class MyDateConverterProvider implements ParamConverterProvider {
  @Override
  public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType,
                                                        Annotation[] annotations) {
      if (rawType == LocalDate.class) {
          return (ParamConverter<T>) new MyDateConverter();
      }
      return null;
  }
}

Using LocalDate in a resource method:

@Path("/")
public class MyResource {

  @GET
  @Path("test8")
  public String readCookie6(@CookieParam("myDateCookie") LocalDate date) {
      return "myDateCookie as LocalDate :" + date;
  }
}

Binding to java.util.Collection

Writing multiple values with the same cookie name:

@Path("/")
public class MyResource {

  @GET
  @Path("test9")
  public Response writeCookies() {
      NewCookie cookie1 = new NewCookie("myCookie", "cookieStrVal");
      NewCookie cookie2 = new NewCookie("myCookie", "cookieStrVal2");
      Response.ResponseBuilder rb = Response.ok(" Multiple values of myCookie"
              + " sent to the browser");
      Response response = rb.cookie(cookie1, cookie2)
                            .build();
      return response;
  }
}

Reading them to a List

@Path("/")
public class MyResource {

  @GET
  @Path("test10")
  public String readCookie7(@CookieParam("myCookie") List<String> list) {
      String rv = "List size: " + list.size() +
              "<br/>List values:<br/> ";
      rv += list.stream()
                .collect(Collectors.joining("<br/>"));
      return rv;
  }
}

Only the last value was used to populate the list. That's because of the same reason as discussed with @HeaderParam.

Using JAX-RS client API to send cookies

public class MyClient {
  public static void main(String[] args) {
      Client client = ClientBuilder.newClient();
      WebTarget target = client.target("http://localhost:8080/test2");
      Invocation.Builder builder = target.request();
      String response = builder.cookie("name1", "value1")
                               .cookie("name2", "value2")
                               .get(String.class);
      System.out.println(response);
      client.close();
  }
}

output

name2 = value2<br/>name1 = value1

Example Project

Dependencies and Technologies Used :

  • jersey-container-servlet 2.25.1: Jersey core Servlet 3.x implementation.
  • JDK 1.8
  • Maven 3.3.9

Cookie Param Examples Select All Download
  • jaxrs-cookie-param
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also