package io.dropwizard.jersey.params;
import com.google.common.base.Strings;
import io.dropwizard.jersey.validation.JerseyParameterNameProvider;
import org.glassfish.jersey.internal.inject.ExtractorException;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
/**
* Provides converters to jersey for dropwizard's *Param classes.
*
* <p>When a param class is used as a resource parameter this converter will instantiate the parameter class with the
* value provided and the name of the parameter, so if value parsing fails the parameter name can be used in the error
* message. If the param class does not have a two-string constructor this provider will return null, causing jersey
* to use the single-string constructor for the parameter type as it normally would.</p>
*/
public class AbstractParamConverterProvider implements ParamConverterProvider {
public AbstractParamConverterProvider() {
}
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if (AbstractParam.class.isAssignableFrom(rawType)) {
final String parameterName = JerseyParameterNameProvider.getParameterNameFromAnnotations(annotations).orElse("Parameter");
final Constructor<T> constructor;
try {
constructor = rawType.getConstructor(String.class, String.class);
} catch (NoSuchMethodException ignored) {
// The Param class did not have a (String, String) constructor. We return null,
// leaving Jersey to handle these parameters as it normally would.
return null;
}
return new ParamConverter<T>() {
@Override
@SuppressWarnings("unchecked")
public T fromString(String value) {
if (rawType != NonEmptyStringParam.class && Strings.isNullOrEmpty(value)) {
return null;
}
try {
return _fromString(value);
} catch (InvocationTargetException ex) {
final Throwable cause = ex.getCause();
if (cause instanceof WebApplicationException) {
throw (WebApplicationException) cause;
} else {
throw new ExtractorException(cause);
}
} catch (final Exception ex) {
throw new ProcessingException(ex);
}
}
protected T _fromString(String value) throws Exception {
return constructor.newInstance(value, parameterName);
}
@Override
public String toString(T value) throws IllegalArgumentException {
if (value == null) {
throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value"));
}
return value.toString();
}
};
}
return null;
}
}