Working with Request and response headers in JAX-RS

[Updated: Apr 3, 2017, Created: Mar 31, 2017]

JAX-RS API provides various ways to access request headers and preparing response headers. In this tutorial we will go through examples to understand the usage.

Accessing Request Header

HttpHeaders example

We can access all headers by using HttpHeaders. The instance of this interface can be injected by using @Context:

@Path("/")
public class TestResource {

  @GET
  @Path("test1")
  public String allHeaders(@Context  HttpHeaders headers) {
      MultivaluedMap<String, String> rh = headers.getRequestHeaders();
      String str = rh.entrySet()
                     .stream()
                     .map(e -> e.getKey() + " = " + e.getValue())
                     .collect(Collectors.joining("<br/>"));

      return str;
  }
}

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

mvn tomcat7:run

HttpHeaders class also has various useful strongly typed methods to get a particular header e.g. get Acceptable Languages(), getCookies(), getLength() etc.

Following is a simple example to get Accept-Language request header value.
@Path("/")
public class TestResource {

      return str;
  }
  @GET
  @Path("test2")
  public String acceptableLanguages(@Context HttpHeaders headers) {
      List<Locale> locales = headers.getAcceptableLanguages();
      return locales.stream()
                    .map(l -> l.toString())
                    .collect(Collectors.joining("<br/>"));
  }
}

@HeaderParam Examples

The annotation @HeaderParam can bind the request header value to a resource method parameter:

@Path("/")
public class TestResource {

  @GET
  @Path("test3")
  public String requestParamTest1(@HeaderParam(HttpHeaders.HOST) String host) {
      return "The request 'host' header value = " + host;
  }
}

Automatic type binding

JAX-RS implicitly binds the request header strings to suitable Java type values. In the following examples, we will explore each options one by one. .

Binding to Java primitives

@Path("/")
public class TestResource {

  @GET
  @Path("test4")
  public String requestParamTest2(@HeaderParam("anInt") int anInteger) {
      return "The request header 'anInt' value: " + anInteger;
  }
}

We are going to use HTTPie to send the custom header 'anInt':

Binding to Java type which has a String accepting constructor

A type which has a String accepting constructor and is annotated with @HeaderParam, can be initialized automatically with the target request header. For example java.util.Date:

new Date("Fri, 3 March 2017 20:35:00 GMT");
@Path("/")
public class TestResource {

  @GET
  @Path("test5")
  public String requestParamTest3(@HeaderParam("aDate") Date date) {
      return "The request  header 'aDate' value:  " + date;
  }
}

A user defined type which has a String constructor parameter can also be used the same way.

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

A type 'T' which has a method with following signature can also be used:

public static T valueOf(String s) { .. }

Java has various classes which have this method e.g. Integer.valueOf(..), Long.valueOf(..) etc. A user defined type can also be used.

In the following example we are going to create a user defined type to demonstrate the usage.

public class DateInfo {
  private Date date;

  public static DateInfo valueOf(String dateStr) {
      if(dateStr==null){
          return null;
      }
      DateInfo dateInfo = new DateInfo();
      dateInfo.date = new Date(dateStr);
      return dateInfo;
  }

  public LocalDateTime asLocalDateTime() {
      return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  }

  public Date asDate() {
      return date;
  }
}
@Path("/")
public class TestResource {

  @GET
  @Path("test6")
  public String valueOfTest(@HeaderParam("aDate") DateInfo dateInfo) {
      return "The request  header 'aDate' converted to LocalDateTime:  " +
              dateInfo.asLocalDateTime();
  }
}

Binding to type which implements ParamConverter

Generally speaking, an implementation of the interface javax. ws. rs. ext. Param Converter can bind any HTTP message attribute (@HeaderParam, @QueryParam, @PathParam, @MatrixParam etc) to a corresponding suitable Java type (predefined or user defined).

Following example shows how to convert LocalDateTime directly (as compared to the last example) by implementing ParamConverter:

public class MyDateConverter implements ParamConverter<LocalDateTime> {
  @Override
  public LocalDateTime fromString(String value) {
      Date date = new Date(value);
      return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  }

  @Override
  public String toString(LocalDateTime value) {
      return value.toString();
  }
}

We also have to implement ParamConverterProvider and annotate it with @Provider so that our custom converter can be discovered and registered during deployment time.

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

Following is the corresponding resource method:

@Path("/")
public class TestResource {

  @GET
  @Path("test7")
  public String paramConverterTest(@HeaderParam("aDate") LocalDateTime date) {
      return "The request  header 'aDate' converted by MyDateConverter:  " + date;
  }
}

Binding to java.util.Collection

We can use a collection (java.util.List, java.util.Set, java.util.SortedSet) as resource method parameter. The elements of the collection can be of any types we have discussed so far. The collection instance is read-only.

@Path("/")
public class TestResource {

  @GET
  @Path("test8")
  public String collectionTest(@HeaderParam("myHeader") List<String> list) {
      String rv = "header collection values: \n";
      rv += list.stream()
                .map(Object::toString)
                .collect(Collectors.joining("\n"));
      return rv;
  }
}

The current version of Jersey (2.25.1) does not split the comma separated headers values into multiple collection elements. Here's a related issue. If client sends multi-line header values (same key) then it is populated as separate collection elements, check out an example here.

Returning headers in response

Methods that need to provide additional metadata with a response should return an instance of Response. The ResponseBuilder class provides a convenient way to create an instance of Response using the builder pattern.

Following example shows how to add response headers using ResponseBuilder:

@Path("/")
public class TestResource {

  @GET
  @Path("test10")
  public Response responseHeaderTest1() {
      Response.ResponseBuilder rb = Response.ok("the test response");
      Response response = rb.header("header1", "value1")
                            .header("header2", "value2")
                            .build();
      return response;
  }
}

Sending request header using JAX-RS Client

Following example shows how to use JAX-RS client API to send request headers to a resource service.

@Path("/")
public class TestResource {

  @GET
  @Path("test10")
  public Response responseHeaderTest1() {
      Response.ResponseBuilder rb = Response.ok("the test response");
      Response response = rb.header("header1", "value1")
                            .header("header2", "value2")
                            .build();
      return response;
  }
  @GET
  @Path("test11")
  public String clientTest(@Context HttpHeaders headers) {
      MultivaluedMap<String, String> rh = headers.getRequestHeaders();
      String str = rh.entrySet()
                     .stream()
                     .map(e -> e.getKey() + " = " + e.getValue())
                     .collect(Collectors.joining("\n"));

      return str;
  }
}
public class MyClient {
  public static void main(String[] args) {
      Client client = ClientBuilder.newClient();
      WebTarget target = client.target("http://localhost:8080/test11");
      Invocation.Builder builder = target.request();
      String response = builder.header("myHeader", "a")
                               .header("aDateHeader", new Date())
                               .get(String.class);
      System.out.println(response);
      client.close();
  }
}

Output

myheader = [a]
adateheader = [Sun, 19 Mar 2017 17:13:28 GMT]
user-agent = [Jersey/2.25.1 (HttpUrlConnection 1.8.0_65)]
host = [localhost:8080]
accept = [text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2]
connection = [keep-alive]

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

Header Param Example Select All Download
  • jaxrs-header-param
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also