package org.jboss.resteasy.plugins.providers;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;

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

import org.jboss.resteasy.annotations.Separator;
import org.jboss.resteasy.core.ResteasyContext;
import org.jboss.resteasy.core.StringParameterInjector;
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.util.Types;

Author:Marek Kopecky mkopecky@redhat.com, Ron Sigal rsigal@redhat.com
/** * @author Marek Kopecky mkopecky@redhat.com * @author Ron Sigal rsigal@redhat.com */
@Provider public class MultiValuedParamConverterProvider implements ParamConverterProvider { private static final Pattern PROXY_REGEX = Pattern.compile("\\p{Punct}|\\[\\p{Punct}+\\]"); @SuppressWarnings("unchecked") @Override public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { if (!isApplicable(annotations)) { return null; } String separator = getSeparator(annotations); Class<?> paramType = getHeaderParam(annotations); if (Collection.class.isAssignableFrom(rawType)) { if (!PROXY_REGEX.matcher(separator).matches()) { LogMessages.LOGGER.invalidRegex(rawType.getName(), separator); return null; } Class<?> type = null; try { type = Types.getTypeArgument(genericType); if (type == null) { return null; } } catch (Exception e) { return null; } Constructor<?> constructor = getConstructor(rawType); if (constructor == null) { return null; } ResteasyProviderFactory factory = ResteasyContext.getContextData(ResteasyProviderFactory.class); StringParameterInjector stringParameterInjector = new StringParameterInjector(type, null, null, paramType, null, null, annotations, factory); return (ParamConverter<T>) new MultiValuedCollectionParamConverter(stringParameterInjector, separator, constructor); } else if (rawType.isArray()) { Class<?> type = rawType.getComponentType(); if (type.isArray() || Collection.class.isAssignableFrom(type)) { return null; } ResteasyProviderFactory factory = ResteasyContext.getContextData(ResteasyProviderFactory.class); StringParameterInjector stringParameterInjector = new StringParameterInjector(type, null, null, paramType, null, null, annotations, factory); return (ParamConverter<T>) new MultiValuedArrayParamConverter(stringParameterInjector, separator, rawType); } return null; } ////////////////////////////////////////////////////////////////////////// private boolean isApplicable(Annotation[] annotations) { if (annotations == null) { return false; } for (Annotation a : annotations) { if (a instanceof Separator) { return true; } } return false; } private Constructor<?> getConstructor(Class<?> clazz) { try { if (List.class.equals(clazz) || ArrayList.class.equals(clazz)) { return ArrayList.class.getConstructor(); } else if (SortedSet.class.equals(clazz) || TreeSet.class.equals(clazz)) { return TreeSet.class.getConstructor(); } else if (Set.class.equals(clazz) || HashSet.class.equals(clazz)) { return HashSet.class.getConstructor(); } else { return null; } } catch (NoSuchMethodException e) { return null; } } private String getSeparator(Annotation[] annotations) { for (Annotation a : annotations) { if (a instanceof Separator) { if ("".equals(((Separator) a).value())) { break; } return ((Separator) a).value(); } } for (Annotation a : annotations) { if (a instanceof CookieParam) { return "-"; } } return ","; } private Class<?> getHeaderParam(Annotation[] annotations) { if (annotations == null) { return null; } for (Annotation a : annotations) { if (a instanceof HeaderParam) { return HeaderParam.class; } } return null; } }