Skip to main content

Jersey (JAX-RS) Java types to consume request parameter values guide

In Jersey (JAX-RS), to consume HTTP request parameter, cookie, header, path variable and matrix parameter string values, we have following options:

  1. Primitive types - int, char, float, long, double, byte and others.
  2. Types with constructor which accepts single String argument.
  3. Types with a static method with name valueOf or fromString which accepts single String argument. For e.g. Integer.valueOf(String) or java.util.UUID.fromString(String).
  4. Types with implementation of ParamConverterProvider JAX-RS extension SPI which return ParamConverter instance. ParamConverter require fromString method implementation, which takes single String argument and convert that to return a specific type. ParamConverterProvider implementation should be registered as provider with Jersey.
  5. List, Set or SortedSet of types defined above. When we expect parameters to have multiple values for same name, we should use these collection.

In this guide we will see examples to create custom Java classes and use them to consume HTTP request parameter values.

Implementation of ParamConverterProvider JAX-RS extension can be used to consume parameters values into existing util classes like Date or LocalDateTime or custom types.

This is a part of Jersey (JAX-RS) Restful Web Services Development Guides series. Please read Jersey + Spring Boot getting started guide.

Java type with single String argument constructor to consume request parameters values

File: ConstructorDateParamModel.java

package in.geekmj.model;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/*
 * 
 * @author geekmj
 * DateParamModel is a class with a constructor with one String Argument
 * We can use it as custom type for mapping request parameters, cookies or headers values 
 */
public class ConstructorDateParamModel {

	private String dateAsString;

	/* Expecting ISO-8601 format date string */
	public ConstructorDateParamModel(String dateAsString) {
		this.dateAsString = dateAsString;

	}

	public LocalDateTime getDate() {
		LocalDateTime dateTime = null;
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE\_TIME);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date time failed.");
		}
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date failed.");
		}

		return dateTime;
	}

}

Above ConstructorDataParamModel can use as type for consuming HTTP request parameter and other values. It has a single String argument constructor. Constructor String argument expected here in ISO Date format. This value parsed with method LocalDateTime.parse(String dateAsString, DateTimeFormatter.ISO_DATE) in another method getDate, which return LocalDateTime object.  When String value is not in ISO Date format, getDate return null value.

Java Type with static method valueOf or fromString to consume request parameters values

File: StaticMethodDateParamModel.java

package in.geekmj.model;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/*
 * 
 * @author geekmj 
 * DateParamModel is a class with a static method valueOf with one String
 * Argument. We can use it as custom type for mapping request parameters,
 * cookies or headers values.
 */
public class StaticMethodDateParamModel {

	private String dateAsString;

	public StaticMethodDateParamModel() {
	}

	public String getDateAsString() {
		return dateAsString;
	}

	public void setDateAsString(String dateAsString) {
		this.dateAsString = dateAsString;
	}

	public LocalDateTime getDate() {
		LocalDateTime dateTime = null;
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE\_TIME);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date time failed.");
		}
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date failed.");
		}

		return dateTime;
	}

	/*
	 * Expecting ISO-8601 format date string
	 *  
	 */
	public static StaticMethodDateParamModel valueOf(String dateAsString) {
		StaticMethodDateParamModel staticMethodDateParamModel = new StaticMethodDateParamModel();
		staticMethodDateParamModel.setDateAsString(dateAsString);
		return staticMethodDateParamModel;
	}

}

Above StaticMethodDateParamModel can use as type for consuming HTTP request parameter and other values. It has a single String argument method valueOf which return StaticMethodDateParamModel instance. Similar to previous class we have getDate method here.

Java Types consuming request parameters values with ParamConverterProvider implementation

File : DateParamModel.java

package in.geekmj.model;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/*
 * 
 * @author geekmj
 * 
 * It is a class with one String attribute dateAsString. Method getDate
 * convert dateAsString to LocalDateTime. We will use it as a custom
 * Type for Request Parameter, Header, Path, Cookie and Matrix values.
 */
public class DateParamModel {

	private String dateAsString;

	public String getDateAsString() {
		return dateAsString;
	}

	public void setDateAsString(String dateAsString) {
		this.dateAsString = dateAsString;
	}

	public LocalDateTime getDate() {
		LocalDateTime dateTime = null;
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE\_TIME);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date time failed.");
		}
		try {
			dateTime = LocalDateTime.parse(dateAsString, DateTimeFormatter.ISO\_DATE);
		} catch (DateTimeParseException ex) {
			System.err.println("Conversion of dateAsString: " + dateAsString + " using ISO date failed.");
		}

		return dateTime;
	}

}

File: DateParamModelConvertorProvider.java

package in.geekmj.config;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;

import in.geekmj.model.DateParamModel;

@Provider
public class DateParamModelConvertorProvider implements ParamConverterProvider {

	@Override
	public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation\[\] annotations) {

		if (rawType.getName().equals(DateParamModel.class.getName())) {
			return new ParamConverter<T>() {

				@SuppressWarnings("unchecked")
				@Override
				public T fromString(String value) {
					DateParamModel dateParamModel = new DateParamModel();
					dateParamModel.setDateAsString(value);
					return (T) dateParamModel;
				}

				@Override
				public String toString(T bean) {
					return ((DateParamModel) bean).getDateAsString();
				}

			};
		}

		return null;
	}

}

Now DateParamModel can used as Type for consuming HTTP request parameter and other values. Observe, DateParamModel don't have single String argument constructor or method. This conversion handled at DateParamModelConvertorProvider level.

Using Custom Java types in Resource

File : CustomTypeParamterConsumeResource.java

package in.geekmj.resource;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.CookieParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.springframework.stereotype.Component;

import in.geekmj.model.ConstructorDateParamModel;
import in.geekmj.model.DateParamModel;
import in.geekmj.model.StaticMethodDateParamModel;

@Path("/custom-type-for-parameters")
@Produces(MediaType.APPLICATION\_JSON)
@Consumes(MediaType.APPLICATION\_JSON)
@Component
public class CustomTypeParamterConsumeResource {

	@QueryParam("datesAsStrings")
	private List<DateParamModel> dateParamModels;

	@CookieParam("dateParamModelAsCookie")
	private StaticMethodDateParamModel cookieDateParamModel;

	@HeaderParam("dateParamModelAsHeader")
	private ConstructorDateParamModel headerDateParamModel;

	@GET
	public Response getCustomType(@QueryParam("dateAsString") DateParamModel dateParamModel) {

		Map<String, Object> result = new HashMap<String, Object>();

		boolean error = false;

		if (dateParamModel != null && dateParamModel.getDate() != null) {
			result.put("dateAsString", dateParamModel.getDate());
		} else if (dateParamModel != null) {
			error = true;
		}

		if (headerDateParamModel != null && headerDateParamModel.getDate() != null) {
			result.put("dateParamModelAsHeader", headerDateParamModel.getDate());
		} else if (headerDateParamModel != null) {
			error = true;
		}

		if (cookieDateParamModel != null && cookieDateParamModel.getDate() != null) {
			result.put("dateParamModelAsCookie", cookieDateParamModel.getDate());
		} else if (cookieDateParamModel != null) {
			error = true;
		}

		if (dateParamModels != null && dateParamModels.size() > 0) {
			List<LocalDateTime> localDateTimes = new ArrayList<LocalDateTime>();

			for (DateParamModel dateParamModelTemp : dateParamModels) {
				if (dateParamModelTemp.getDate() != null) {
					localDateTimes.add(dateParamModelTemp.getDate());
				} else {
					error = true;
				}
			}

			result.put("datesAsStrings", localDateTimes);
		}

		return error ? Response.status(Status.BAD\_REQUEST)
				.entity("{'error:'Expected dateAsString in ISO DATE format''}").build()
				: Response.ok().entity(result).build();
	}

}

Above Resource takes ISO Date strings as request parameter, cookie and header values. In response it returns a JSON with dates detail.

Testing GET request for URL https://localhost:8080/custom-type-for-parameters?dateAsString=1994-11-05T08:15:30%2B01:00&datesAsStrings=2016-01-03T10:15:30&datesAsStrings=2016-01-03T10:15:30 with Postman chrome plugin.

Postman HTTP Request & Response for API URI custom-type-for-parameters

References

  1. Official Jersey Documentation

  2. Download the Full Project

  3. Follow Project On Github

Comments

Popular posts from this blog

Working with request header in Jersey (JAX-RS) guide

In the  previous post , we talked about, how to get parameters and their values from the request query string. In this guide learn how to get request header values in Jersey (JAX-RS) based application. We had tested or used the following tools and technologies in this project: Jersey (v 2.21) Gradle Build System (v 2.9) Spring Boot (v 1.3) Java (v 1.8) Eclipse IDE This is a part of  Jersey (JAX-RS) Restful Web Services Development Guides series. Please read Jersey + Spring Boot getting started guide . Gradle Build File We are using Gradle for our build and dependency management (Using Maven rather than Gradle is a very trivial task). File: build.gradle buildscript { ext { springBootVersion = '1.3.0.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' a

Ajax Cross Domain Resource Access Using jQuery

Some time back in our project we faced a problem while making an Ajax call using jQuery. Chrome Browser console had given some weird error message like below when we try to access one of our web pages: When we try to access the same web page in the Firefox browser, it doesn't give any error in the console but some parsing error occurred. In our case, we were accessing XML as an Ajax request resource. I was curious to check if the non-XML cross-domain resource was successfully loading or not. But finally, I realized that it is not going through. jersey-spring-boot-quick-starter-guide In our Ajax call, requesting domain was not the same as the requested URL domain. $.ajax({ url: "https://10.11.2.171:81/xxxxxx/xxxxxxx.xml" , type : "get" , success: function (response) { alert( "Load was performed." ); }, error : function (xhr, status) {

FastAPI first shot

Setup on my Mac (Macbook Pro 15 inch Retina, Mid 2014) Prerequisite Python 3.6+ (I used 3.7.x. I recently reinstalled OS after cleaning up disk, where stock Python 2.7 was available. I installed Pyenv and then used it to install 3.7.x). I already had a git repo initialized at Github for this project. I checked that out. I use this approach to keep all the source code safe or at a specific place 😀. I set the Python version in .python-version file. I also initialize the virtual environment using pyenv in venv folder. I started the virtual environment. FastAPI specific dependencies setup Now I started with basic pip commands to install dependency for the project. I saved dependencies in requirements.txt  the file. Minimal viable code to spin an API Server FastAPI is as cool as NodeJS or Go Lang (?) to demonstrate the ability to spin an API endpoint up and running in no time. I had the same feeling for the Flask too, which was also super cool. app/main.py: from typing i