ClientQueryParamMarshaller.java

package org.xandercat.pmdb.ws;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.ws.rs.QueryParam;
import javax.ws.rs.client.WebTarget;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
 * Jersey and the ws.rs.Client api do not appear to have any means to utilize an annotated class to populate query parameters for a
 * Client GET request.  This class provides that capability by reusing the QueryParam annotation as a means to set request parameters
 * for a request.  For a query parameter to be set, the field must be annotated with QueryParam and the value must be non-blank.
 * 
 * @author Scott Arnold
 */
public class ClientQueryParamMarshaller {
	
	/**
	 * Return a query param map from a QueryParam annotated class object.
	 * 
	 * @param object object to produce a query param map from
	 * 
	 * @return query param map for the object
	 */
	public Map<String, String> queryParamMap(Object object) {
		Field[] fields = object.getClass().getDeclaredFields();
		List<Field> paramFields = Arrays.stream(fields)
				.filter(field -> StringUtils.hasText((String) AnnotationUtils.getValue(field.getDeclaredAnnotation(QueryParam.class))))
				.collect(Collectors.toList());
		paramFields.forEach(field -> ReflectionUtils.makeAccessible(field));
		return paramFields.stream()
				.collect(Collectors.toMap(field -> field, field -> (String) AnnotationUtils.getValue(field.getDeclaredAnnotation(QueryParam.class))))
				.entrySet().stream()
				.filter(entry -> ReflectionUtils.getField(entry.getKey(), object) != null)
				.filter(entry -> StringUtils.hasText(ReflectionUtils.getField(entry.getKey(), object).toString()))
				.collect(Collectors.toMap(Map.Entry::getValue, entry -> ReflectionUtils.getField(entry.getKey(), object).toString()));		
	}
	
	/**
	 * Configure a WebTarget with query parameters from the provided QueryParam annotated class object.
	 * 
	 * @param webTarget WebTarget to configure with query parameters
	 * @param object QueryParam annotated class object to pull query parameters from
	 * 
	 * @return WebTarget configured with query parameters from provided QueryParam annotated class object
	 */
	public WebTarget queryParams(WebTarget webTarget, Object object) {
		Map<String, String> queryParams = queryParamMap(object);
		for (Map.Entry<String, String> entry : queryParams.entrySet()) {
			webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
		}
		return webTarget;
	}
}