Skip to content

Commit 895c293

Browse files
authored
Put Parameter class in core-common, to be used by both client and server (#4091)
* Created Parameter class in core-common, to be used by both client and server Signed-off-by: Jan Supol <jan.supol@oracle.com> * putback AnnotatedMethod Signed-off-by: Jan Supol <jan.supol@oracle.com> * Make sure the ParameterServiceProvider from core-server is the first in the list Signed-off-by: Jan Supol <jan.supol@oracle.com>
1 parent 38c1c6d commit 895c293

File tree

8 files changed

+1231
-827
lines changed

8 files changed

+1231
-827
lines changed
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
/*
2+
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.jersey.model;
18+
19+
import org.glassfish.jersey.internal.util.ReflectionHelper;
20+
21+
import javax.ws.rs.Consumes;
22+
import javax.ws.rs.CookieParam;
23+
import javax.ws.rs.DefaultValue;
24+
import javax.ws.rs.Encoded;
25+
import javax.ws.rs.FormParam;
26+
import javax.ws.rs.HeaderParam;
27+
import javax.ws.rs.HttpMethod;
28+
import javax.ws.rs.MatrixParam;
29+
import javax.ws.rs.Path;
30+
import javax.ws.rs.PathParam;
31+
import javax.ws.rs.Produces;
32+
import javax.ws.rs.QueryParam;
33+
import javax.ws.rs.core.Context;
34+
import java.lang.annotation.Annotation;
35+
import java.lang.reflect.AnnotatedElement;
36+
import java.lang.reflect.Method;
37+
import java.lang.reflect.Type;
38+
import java.lang.reflect.TypeVariable;
39+
import java.security.AccessController;
40+
import java.util.ArrayList;
41+
import java.util.Arrays;
42+
import java.util.HashSet;
43+
import java.util.List;
44+
import java.util.Set;
45+
46+
/**
47+
* Annotated method representation.
48+
*
49+
* @author Paul Sandoz
50+
*/
51+
public class AnnotatedMethod implements AnnotatedElement {
52+
53+
@SuppressWarnings("unchecked")
54+
private static final Set<Class<? extends Annotation>> METHOD_META_ANNOTATIONS = getSet(
55+
HttpMethod.class);
56+
@SuppressWarnings("unchecked")
57+
private static final Set<Class<? extends Annotation>> METHOD_ANNOTATIONS = getSet(
58+
Path.class,
59+
Produces.class,
60+
Consumes.class);
61+
@SuppressWarnings("unchecked")
62+
private static final Set<Class<? extends Annotation>> PARAMETER_ANNOTATIONS = getSet(
63+
Context.class,
64+
Encoded.class,
65+
DefaultValue.class,
66+
MatrixParam.class,
67+
QueryParam.class,
68+
CookieParam.class,
69+
HeaderParam.class,
70+
PathParam.class,
71+
FormParam.class);
72+
73+
@SafeVarargs
74+
private static Set<Class<? extends Annotation>> getSet(final Class<? extends Annotation>... cs) {
75+
final Set<Class<? extends Annotation>> s = new HashSet<>();
76+
s.addAll(Arrays.asList(cs));
77+
return s;
78+
}
79+
80+
private final Method m;
81+
private final Method am;
82+
private final Annotation[] methodAnnotations;
83+
private final Annotation[][] parameterAnnotations;
84+
85+
/**
86+
* Create annotated method instance from the {@link Method Java method}.
87+
*
88+
* @param method Java method.
89+
*/
90+
public AnnotatedMethod(final Method method) {
91+
this.m = method;
92+
this.am = findAnnotatedMethod(method);
93+
94+
if (method.equals(am)) {
95+
methodAnnotations = method.getAnnotations();
96+
parameterAnnotations = method.getParameterAnnotations();
97+
} else {
98+
methodAnnotations = mergeMethodAnnotations(method, am);
99+
parameterAnnotations = mergeParameterAnnotations(method, am);
100+
}
101+
}
102+
103+
/**
104+
* Get the underlying Java method.
105+
*
106+
* @return the underlying Java method.
107+
*/
108+
public Method getMethod() {
109+
return am;
110+
}
111+
112+
/**
113+
* Get the underlying declared Java method. This method overrides or is the same as the one retrieved by {@code getMethod}.
114+
*
115+
* @return the underlying declared Java method.
116+
*/
117+
public Method getDeclaredMethod() {
118+
return m;
119+
}
120+
121+
/**
122+
* Get method parameter annotations.
123+
*
124+
* @return method parameter annotations.
125+
*/
126+
public Annotation[][] getParameterAnnotations() {
127+
return parameterAnnotations.clone();
128+
}
129+
130+
/**
131+
* Get method parameter types.
132+
*
133+
* See also {@link Method#getParameterTypes()}.
134+
*
135+
* @return method parameter types.
136+
*/
137+
public Class<?>[] getParameterTypes() {
138+
return am.getParameterTypes();
139+
}
140+
141+
/**
142+
* Get method type parameters.
143+
*
144+
* See also {@link Method#getTypeParameters()}.
145+
*
146+
* @return method type parameters.
147+
*/
148+
@SuppressWarnings("UnusedDeclaration")
149+
public TypeVariable<Method>[] getTypeParameters() {
150+
return am.getTypeParameters();
151+
}
152+
153+
/**
154+
* Get generic method parameter types.
155+
*
156+
* See also {@link Method#getGenericParameterTypes()}.
157+
*
158+
* @return generic method parameter types.
159+
*/
160+
public Type[] getGenericParameterTypes() {
161+
return am.getGenericParameterTypes();
162+
}
163+
164+
/**
165+
* Get all instances of the specified meta-annotation type found on the method
166+
* annotations.
167+
*
168+
* @param <T> meta-annotation type.
169+
* @param annotation meta-annotation class to be searched for.
170+
* @return meta-annotation instances of a given type annotating the method
171+
* annotations.
172+
*/
173+
public <T extends Annotation> List<T> getMetaMethodAnnotations(
174+
final Class<T> annotation) {
175+
final List<T> ma = new ArrayList<>();
176+
for (final Annotation a : methodAnnotations) {
177+
final T metaAnnotation = a.annotationType().getAnnotation(annotation);
178+
if (metaAnnotation != null) {
179+
ma.add(metaAnnotation);
180+
}
181+
}
182+
183+
return ma;
184+
}
185+
186+
@Override
187+
public String toString() {
188+
return m.toString();
189+
}
190+
191+
// AnnotatedElement
192+
@Override
193+
public boolean isAnnotationPresent(final Class<? extends Annotation> annotationType) {
194+
for (final Annotation ma : methodAnnotations) {
195+
if (ma.annotationType() == annotationType) {
196+
return true;
197+
}
198+
}
199+
return false;
200+
}
201+
202+
@Override
203+
public <T extends Annotation> T getAnnotation(final Class<T> annotationType) {
204+
for (final Annotation ma : methodAnnotations) {
205+
if (ma.annotationType() == annotationType) {
206+
return annotationType.cast(ma);
207+
}
208+
}
209+
return am.getAnnotation(annotationType);
210+
}
211+
212+
@Override
213+
public Annotation[] getAnnotations() {
214+
return methodAnnotations.clone();
215+
}
216+
217+
@Override
218+
public Annotation[] getDeclaredAnnotations() {
219+
return getAnnotations();
220+
}
221+
222+
private static Annotation[] mergeMethodAnnotations(final Method m, final Method am) {
223+
final List<Annotation> al = asList(m.getAnnotations());
224+
for (final Annotation a : am.getAnnotations()) {
225+
if (!m.isAnnotationPresent(a.getClass())) {
226+
al.add(a);
227+
}
228+
}
229+
230+
return al.toArray(new Annotation[al.size()]);
231+
}
232+
233+
private static Annotation[][] mergeParameterAnnotations(final Method m, final Method am) {
234+
final Annotation[][] methodParamAnnotations = m.getParameterAnnotations();
235+
final Annotation[][] annotatedMethodParamAnnotations = am.getParameterAnnotations();
236+
237+
final List<List<Annotation>> methodParamAnnotationsList = new ArrayList<>();
238+
for (int i = 0; i < methodParamAnnotations.length; i++) {
239+
final List<Annotation> al = asList(methodParamAnnotations[i]);
240+
for (final Annotation a : annotatedMethodParamAnnotations[i]) {
241+
if (annotationNotInList(a.getClass(), al)) {
242+
al.add(a);
243+
}
244+
}
245+
methodParamAnnotationsList.add(al);
246+
}
247+
248+
final Annotation[][] mergedAnnotations = new Annotation[methodParamAnnotations.length][];
249+
for (int i = 0; i < methodParamAnnotations.length; i++) {
250+
final List<Annotation> paramAnnotations = methodParamAnnotationsList.get(i);
251+
mergedAnnotations[i] = paramAnnotations.toArray(new Annotation[paramAnnotations.size()]);
252+
}
253+
254+
return mergedAnnotations;
255+
}
256+
257+
private static boolean annotationNotInList(final Class<? extends Annotation> ca, final List<Annotation> la) {
258+
for (final Annotation a : la) {
259+
if (ca == a.getClass()) {
260+
return false;
261+
}
262+
}
263+
return true;
264+
}
265+
266+
private static Method findAnnotatedMethod(final Method m) {
267+
final Method am = findAnnotatedMethod(m.getDeclaringClass(), m);
268+
return (am != null) ? am : m;
269+
}
270+
271+
private static Method findAnnotatedMethod(final Class<?> c, Method m) {
272+
if (c == Object.class) {
273+
return null;
274+
}
275+
276+
m = AccessController.doPrivileged(ReflectionHelper.findMethodOnClassPA(c, m));
277+
if (m == null) {
278+
return null;
279+
}
280+
281+
if (hasAnnotations(m)) {
282+
return m;
283+
}
284+
285+
// Super classes take precedence over interfaces
286+
final Class<?> sc = c.getSuperclass();
287+
if (sc != null && sc != Object.class) {
288+
final Method sm = findAnnotatedMethod(sc, m);
289+
if (sm != null) {
290+
return sm;
291+
}
292+
}
293+
294+
for (final Class<?> ic : c.getInterfaces()) {
295+
final Method im = findAnnotatedMethod(ic, m);
296+
if (im != null) {
297+
return im;
298+
}
299+
}
300+
301+
return null;
302+
}
303+
304+
private static boolean hasAnnotations(final Method m) {
305+
return hasMetaMethodAnnotations(m)
306+
|| hasMethodAnnotations(m)
307+
|| hasParameterAnnotations(m);
308+
}
309+
310+
private static boolean hasMetaMethodAnnotations(final Method m) {
311+
for (final Class<? extends Annotation> ac : METHOD_META_ANNOTATIONS) {
312+
for (final Annotation a : m.getAnnotations()) {
313+
if (a.annotationType().getAnnotation(ac) != null) {
314+
return true;
315+
}
316+
}
317+
}
318+
319+
return false;
320+
}
321+
322+
private static boolean hasMethodAnnotations(final Method m) {
323+
for (final Class<? extends Annotation> ac : METHOD_ANNOTATIONS) {
324+
if (m.isAnnotationPresent(ac)) {
325+
return true;
326+
}
327+
}
328+
329+
return false;
330+
}
331+
332+
private static boolean hasParameterAnnotations(final Method m) {
333+
for (final Annotation[] as : m.getParameterAnnotations()) {
334+
for (final Annotation a : as) {
335+
if (PARAMETER_ANNOTATIONS.contains(a.annotationType())) {
336+
return true;
337+
}
338+
}
339+
}
340+
341+
return false;
342+
}
343+
344+
@SafeVarargs
345+
private static <T> List<T> asList(final T... ts) {
346+
final List<T> l = new ArrayList<>();
347+
l.addAll(Arrays.asList(ts));
348+
return l;
349+
}
350+
}

0 commit comments

Comments
 (0)