org.glassfish.jersey.model.Parameter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxrs-ri Show documentation
Show all versions of jaxrs-ri Show documentation
A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle
(jaxrs-ri.jar).
Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and
contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external
RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source
bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external
RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI
sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from
the command line.
/*
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.model;
import org.glassfish.jersey.internal.LocalizationMessages;
import org.glassfish.jersey.internal.ServiceFinder;
import org.glassfish.jersey.internal.guava.Lists;
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.collection.ClassTypePair;
import org.glassfish.jersey.model.internal.spi.ParameterServiceProvider;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.CookieParam;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.Encoded;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.MatrixParam;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.container.Suspended;
import jakarta.ws.rs.core.Context;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class Parameter implements AnnotatedElement {
private static final Logger LOGGER = Logger.getLogger(Parameter.class.getName());
/**
* Parameter injection sources type.
*/
public enum Source {
/**
* Context parameter injection source.
*/
CONTEXT,
/**
* Cookie parameter injection source.
*/
COOKIE,
/**
* Entity parameter injection source.
*/
ENTITY,
/**
* Form parameter injection source.
*/
FORM,
/**
* Header parameter injection source.
*/
HEADER,
/**
* Uri parameter injection source.
*/
URI,
/**
* Matrix parameter injection source.
*/
MATRIX,
/**
* Path parameter injection source.
*/
PATH,
/**
* Query parameter injection source.
*/
QUERY,
/**
* Suspended async response injection source.
*/
SUSPENDED,
/**
* Bean param parameter injection source.
*/
BEAN_PARAM,
/**
* Unknown parameter injection source.
*/
UNKNOWN
}
static {
List PARAMETER_SERVICE_PROVIDERS = Lists
.newArrayList(ServiceFinder.find(ParameterServiceProvider.class));
PARAMETER_SERVICE_PROVIDERS.add(new ParameterService());
PARAM_CREATION_FACTORIES = Collections.unmodifiableList(
PARAMETER_SERVICE_PROVIDERS.stream().map(a -> a.getParameterCreationFactory())
.collect(Collectors.toList())
);
ANNOTATION_HELPER_MAP = Collections.unmodifiableMap(
PARAMETER_SERVICE_PROVIDERS.stream()
.map(a -> a.getParameterAnnotationHelperMap())
.collect(WeakHashMap::new, Map::putAll, Map::putAll)
);
};
private static final List PARAM_CREATION_FACTORIES;
private static final Map ANNOTATION_HELPER_MAP;
public interface ParamAnnotationHelper {
public String getValueOf(T a);
public Parameter.Source getSource();
}
/**
* A factory service to found in a runtime to be used to instantiate the given {@link Parameter} class.
* @param the {@code Parameter} to be instatiated
*/
public interface ParamCreationFactory {
/**
* Determine whether the Factory is for the given class to be instantiated.
* @param clazz The class of determining the source of origin (core, server). Each source of origin
* has its own {@code ParamCreationFactory}
* @return {@code true} if the source of origin corresponds to the {@code ParamCreationFactory},
* {@code false} otherwise.
*/
boolean isFor(Class> clazz);
/**
* Factory method to instantiate {@link Parameter} of given properties
* @return instantiated {@code Parameter}
*/
PARAMETER createParameter(Annotation[] markers, Annotation marker, Source source, String sourceName, Class> rawType,
Type type, boolean encoded, String defaultValue);
/**
* Factory method to instantiate {@code BeanParameter} of given properties
* @return instantiated {@code BeanParameter}
*/
PARAMETER createBeanParameter(Annotation[] markers, Annotation marker, Source source, String sourceName, Class> rawType,
Type type, boolean encoded, String defaultValue);
}
// Instance
private final Annotation[] annotations;
private final Annotation sourceAnnotation;
private final Parameter.Source source;
private final String sourceName;
private final boolean encoded;
private final String defaultValue;
private final Class> rawType;
private final Type type;
protected Parameter(
Annotation[] markers,
Annotation marker,
Source source,
String sourceName,
Class> rawType,
Type type,
boolean encoded,
String defaultValue) {
this.annotations = markers;
this.sourceAnnotation = marker;
this.source = source;
this.sourceName = sourceName;
this.rawType = rawType;
this.type = type;
this.encoded = encoded;
this.defaultValue = defaultValue;
}
/**
* Create a parameter model.
*
* @param concreteClass concrete resource method handler implementation class.
* @param declaringClass declaring class of the method the parameter belongs to or field that this parameter represents.
* @param encodeByDefault flag indicating whether the parameter should be encoded by default or not. Note that a presence
* of {@link Encoded} annotation in the list of the parameter {@code annotations} will override any
* value set in the flag to {@code true}.
* @param rawType raw Java parameter type.
* @param type generic Java parameter type.
* @param annotations parameter annotations.
* @return new parameter model.
*/
@SuppressWarnings("unchecked")
public static PARAMETER create(
Class concreteClass,
Class declaringClass,
boolean encodeByDefault,
Class> rawType,
Type type,
Annotation[] annotations) {
return (PARAMETER) create(concreteClass, declaringClass, encodeByDefault, rawType, type, annotations, Parameter.class);
}
/**
* Create a parameter model.
*
* @param concreteClass concrete resource method handler implementation class.
* @param declaringClass declaring class of the method the parameter belongs to or field that this parameter represents.
* @param encodeByDefault flag indicating whether the parameter should be encoded by default or not. Note that a presence
* of {@link Encoded} annotation in the list of the parameter {@code annotations} will override any
* value set in the flag to {@code true}.
* @param rawType raw Java parameter type.
* @param type generic Java parameter type.
* @param annotations parameter annotations.
* @param parameterClass class of the parameter to be used by {@link ParamCreationFactory}
* @return new parameter model.
*/
@SuppressWarnings("unchecked")
protected static PARAMETER create(
Class concreteClass,
Class declaringClass,
boolean encodeByDefault,
Class> rawType,
Type type,
Annotation[] annotations,
Class> parameterClass) {
if (null == annotations) {
return null;
}
Annotation paramAnnotation = null;
Parameter.Source paramSource = null;
String paramName = null;
boolean paramEncoded = encodeByDefault;
String paramDefault = null;
/**
* Create a parameter from the list of annotations. Unknown annotated
* parameters are also supported, and in such a cases the last
* unrecognized annotation is taken to be that associated with the
* parameter.
*/
for (Annotation annotation : annotations) {
if (ANNOTATION_HELPER_MAP.containsKey(annotation.annotationType())) {
ParamAnnotationHelper helper = ANNOTATION_HELPER_MAP.get(annotation.annotationType());
paramAnnotation = annotation;
paramSource = helper.getSource();
paramName = helper.getValueOf(annotation);
} else if (Encoded.class == annotation.annotationType()) {
paramEncoded = true;
} else if (DefaultValue.class == annotation.annotationType()) {
paramDefault = ((DefaultValue) annotation).value();
} else {
// Take latest unknown annotation, but don't override known annotation
if ((paramAnnotation == null) || (paramSource == Source.UNKNOWN)) {
paramAnnotation = annotation;
paramSource = Source.UNKNOWN;
paramName = getValue(annotation);
}
}
}
if (paramAnnotation == null) {
paramSource = Parameter.Source.ENTITY;
}
ClassTypePair ct = ReflectionHelper.resolveGenericType(
concreteClass, declaringClass, rawType, type);
if (paramSource == Source.BEAN_PARAM) {
return createBeanParameter(
annotations,
paramAnnotation,
paramSource,
paramName,
ct.rawClass(),
ct.type(),
paramEncoded,
paramDefault,
parameterClass);
} else {
return createParameter(
annotations,
paramAnnotation,
paramSource,
paramName,
ct.rawClass(),
ct.type(),
paramEncoded,
paramDefault,
parameterClass);
}
}
private static PARAMETER createBeanParameter(Annotation[] markers, Annotation marker,
Source source, String sourceName,
Class> rawType, Type type, boolean encoded,
String defaultValue,
Class> parameterClass) {
for (ParamCreationFactory> factory : PARAM_CREATION_FACTORIES) {
if (factory.isFor(parameterClass)) {
return (PARAMETER) factory.createBeanParameter(markers, marker, source, sourceName, rawType, type, encoded,
defaultValue);
}
}
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER, LocalizationMessages.PARAM_CREATION_FACTORY_NOT_FOUND(parameterClass.getName()));
}
throw new IllegalStateException(LocalizationMessages.PARAM_CREATION_FACTORY_NOT_FOUND(parameterClass.getName()));
}
private static PARAMETER createParameter(Annotation[] markers, Annotation marker,
Source source, String sourceName, Class> rawType,
Type type, boolean encoded, String defaultValue,
Class> parameterClass) {
for (ParamCreationFactory> factory : PARAM_CREATION_FACTORIES) {
if (factory.isFor(parameterClass)) {
return (PARAMETER) factory.createParameter(markers, marker, source, sourceName, rawType, type, encoded,
defaultValue);
}
}
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER, LocalizationMessages.PARAM_CREATION_FACTORY_NOT_FOUND(parameterClass.getName()));
}
throw new IllegalStateException(LocalizationMessages.PARAM_CREATION_FACTORY_NOT_FOUND(parameterClass.getName()));
}
/**
* Create a list of parameter models for a given Java method handling a resource
* method, sub-resource method or a sub-resource locator.
*
* @param concreteClass concrete resource method handler implementation class.
* @param declaringClass the class declaring the handling Java method.
* @param javaMethod Java method handling a resource method, sub-resource
* method or a sub-resource locator.
* @param keepEncoded set to {@code true} to disable automatic decoding
* of all the method parameters. (See {@link Encoded}.
* @return a list of handling method parameter models.
*/
public static List create(
Class concreteClass,
Class declaringClass,
Method javaMethod,
boolean keepEncoded) {
return createList(concreteClass, declaringClass, javaMethod, keepEncoded, Parameter.class);
}
/**
* Create a list of parameter models for a given Java method handling a resource
* method, sub-resource method or a sub-resource locator.
*
* @param concreteClass concrete resource method handler implementation class.
* @param declaringClass the class declaring the handling Java method.
* @param javaMethod Java method handling a resource method, sub-resource
* method or a sub-resource locator.
* @param keepEncoded set to {@code true} to disable automatic decoding
* of all the method parameters. (See {@link Encoded}.
* @param parameterClass Class of a Parameter in returned list
* @return a list of handling method parameter models.
*/
protected static List createList(
Class concreteClass,
Class declaringClass,
Method javaMethod,
boolean keepEncoded,
Class parameterClass) {
AnnotatedMethod method = new AnnotatedMethod(javaMethod);
return createList(
concreteClass, declaringClass,
((null != method.getAnnotation(Encoded.class)) || keepEncoded),
method.getParameterTypes(),
method.getGenericParameterTypes(),
method.getParameterAnnotations(),
parameterClass);
}
private static List createList(Class concreteClass, Class declaringClass,
boolean keepEncoded, Class[] parameterTypes,
Type[] genericParameterTypes,
Annotation[][] parameterAnnotations,
Class> parameterClass) {
final List parameters = new ArrayList<>(parameterTypes.length);
for (int i = 0; i < parameterTypes.length; i++) {
final PARAMETER parameter = Parameter.create(concreteClass, declaringClass, keepEncoded, parameterTypes[i],
genericParameterTypes[i], parameterAnnotations[i], parameterClass);
if (null != parameter) {
parameters.add(parameter);
} else {
// TODO throw IllegalStateException instead?
return Collections.emptyList();
}
}
return parameters;
}
/**
* Create a list of parameter models for a given resource method handler
* injectable constructor.
*
* @param concreteClass concrete resource method handler implementation class.
* @param declaringClass class where the method has been declared.
* @param ctor injectable constructor of the resource method handler.
* @param keepEncoded set to {@code true} to disable automatic decoding
* of all the constructor parameters. (See {@link Encoded}.
* @return a list of constructor parameter models.
*/
protected static List createList(
Class concreteClass,
Class declaringClass,
Constructor> ctor,
boolean keepEncoded,
Class> parameterClass) {
Class[] parameterTypes = ctor.getParameterTypes();
Type[] genericParameterTypes = ctor.getGenericParameterTypes();
// Workaround bug http://bugs.sun.com/view_bug.do?bug_id=5087240
if (parameterTypes.length != genericParameterTypes.length) {
Type[] _genericParameterTypes = new Type[parameterTypes.length];
_genericParameterTypes[0] = parameterTypes[0];
System.arraycopy(genericParameterTypes, 0, _genericParameterTypes, 1, genericParameterTypes.length);
genericParameterTypes = _genericParameterTypes;
}
return createList(
concreteClass, declaringClass,
((null != ctor.getAnnotation(Encoded.class)) || keepEncoded),
parameterTypes,
genericParameterTypes,
ctor.getParameterAnnotations(),
parameterClass);
}
private static String getValue(Annotation a) {
try {
Method m = a.annotationType().getMethod("value");
if (m.getReturnType() != String.class) {
return null;
}
return (String) m.invoke(a);
} catch (Exception ex) {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER,
String.format("Unable to get the %s annotation value property", a.getClass().getName()), ex);
}
}
return null;
}
/**
* Get the parameter source annotation.
*
* @return parameter source annotation.
*/
public Annotation getSourceAnnotation() {
return sourceAnnotation;
}
/**
* Get the parameter value source type.
*
* @return parameter value source type.
*/
public Parameter.Source getSource() {
return source;
}
/**
* Get the parameter source name, i.e. value of the parameter source annotation.
*
* @return parameter source name.
*/
public String getSourceName() {
return sourceName;
}
/**
* If {@code true}, the injected parameter value should remain encoded.
*
* @return {@code true} if the parameter value should remain encoded,
* {@code false} otherwise.
*/
public boolean isEncoded() {
return encoded;
}
/**
* Check if the parameter has a default value set.
*
* @return {@code true} if the default parameter value has been set,
* {@code false} otherwise.
*/
public boolean hasDefaultValue() {
return defaultValue != null;
}
/**
* Get the default parameter value.
*
* @return default parameter value or {@code null} if no default value has
* been set for the parameter.
*/
public String getDefaultValue() {
return defaultValue;
}
/**
* Get raw type information for the parameter.
*
* @return raw parameter type information.
*/
public Class> getRawType() {
return rawType;
}
/**
* Get generic type information for the parameter.
*
* @return generic parameter type information.
*/
public Type getType() {
return type;
}
/**
* Check if the parameter is qualified.
*
* @return {@code false}.
*/
public boolean isQualified() {
return false;
}
@Override
public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
@Override
public T getAnnotation(Class annotationClass) {
if (annotationClass == null) {
return null;
}
for (Annotation a : annotations) {
if (a.annotationType() == annotationClass) {
return annotationClass.cast(a);
}
}
return null;
}
@Override
public Annotation[] getAnnotations() {
return annotations.clone();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return annotations.clone();
}
@Override
public String toString() {
return String.format("Parameter [type=%s, source=%s, defaultValue=%s]",
getRawType(), getSourceName(), getDefaultValue());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Parameter parameter = (Parameter) o;
if (encoded != parameter.encoded) {
return false;
}
if (!Arrays.equals(annotations, parameter.annotations)) {
return false;
}
if (defaultValue != null ? !defaultValue.equals(parameter.defaultValue) : parameter.defaultValue != null) {
return false;
}
if (rawType != null ? !rawType.equals(parameter.rawType) : parameter.rawType != null) {
return false;
}
if (source != parameter.source) {
return false;
}
if (sourceAnnotation != null ? !sourceAnnotation.equals(parameter.sourceAnnotation) : parameter.sourceAnnotation
!= null) {
return false;
}
if (sourceName != null ? !sourceName.equals(parameter.sourceName) : parameter.sourceName != null) {
return false;
}
if (type != null ? !type.equals(parameter.type) : parameter.type != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = annotations != null ? Arrays.hashCode(annotations) : 0;
result = 31 * result + (sourceAnnotation != null ? sourceAnnotation.hashCode() : 0);
result = 31 * result + (source != null ? source.hashCode() : 0);
result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0);
result = 31 * result + (encoded ? 1 : 0);
result = 31 * result + (defaultValue != null ? defaultValue.hashCode() : 0);
result = 31 * result + (rawType != null ? rawType.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
public static class ParameterService implements ParameterServiceProvider {
@Override
public Map getParameterAnnotationHelperMap() {
Map m = new WeakHashMap();
m.put(Context.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(Context a) {
return null;
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.CONTEXT;
}
});
m.put(CookieParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(CookieParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.COOKIE;
}
});
m.put(FormParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(FormParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.FORM;
}
});
m.put(HeaderParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(HeaderParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.HEADER;
}
});
m.put(MatrixParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(MatrixParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.MATRIX;
}
});
m.put(PathParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(PathParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.PATH;
}
});
m.put(QueryParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(QueryParam a) {
return a.value();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.QUERY;
}
});
m.put(Suspended.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(Suspended a) {
return Suspended.class.getName();
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.SUSPENDED;
}
});
m.put(BeanParam.class, new ParamAnnotationHelper() {
@Override
public String getValueOf(BeanParam a) {
return null;
}
@Override
public Parameter.Source getSource() {
return Parameter.Source.BEAN_PARAM;
}
});
return m;
}
@Override
public ParamCreationFactory getParameterCreationFactory() {
return new ParamCreationFactory() {
@Override
public boolean isFor(Class> clazz) {
return clazz == Parameter.class;
}
@Override
public Parameter createParameter(Annotation[] markers, Annotation marker, Source source, String sourceName,
Class> rawType, Type type, boolean encoded, String defaultValue) {
return new Parameter(markers, marker, source, sourceName, rawType, type, encoded, defaultValue);
}
@Override
public Parameter createBeanParameter(Annotation[] markers, Annotation marker, Source source, String sourceName,
Class> rawType, Type type, boolean encoded, String defaultValue) {
return createParameter(markers, marker, source, sourceName, rawType, type, encoded, defaultValue);
}
};
}
}
}