1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.lang3.reflect;
19
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22
23 import java.lang.reflect.Method;
24
25 import org.junit.jupiter.api.Test;
26
27 /**
28 * Tests {@link MethodUtils#getAnnotation(Method, Class, boolean, boolean)}.
29 * <p>
30 * getMatchingMethod allows assignable params, potentially finding annotations on unrelated overloads.
31 * </p>
32 */
33 public class MethodUtilsAnnotationsTest {
34
35 /** Interface with a method taking Number, annotated @Deprecated */
36 public interface Processor {
37
38 @SuppressWarnings("javadoc")
39 @Deprecated
40 void process(Number n);
41 }
42
43 /** Implementation that does NOT annotate process(Integer) */
44 public static class ProcessorImpl implements Processor {
45
46 // Overload with Integer â NOT annotated
47 @SuppressWarnings("javadoc")
48 public void process(final Integer i) {
49 // intentionally no @Deprecated
50 }
51
52 @SuppressWarnings("deprecation")
53 @Override
54 public void process(final Number n) {
55 // inherited, annotated on interface
56 }
57 }
58
59 /**
60 * getAnnotation() for process(Integer) should return null because the Integer overload is NOT an override of process(Number).
61 * <ul>
62 * <li>Pre-patch: getMatchingMethod finds process(Number) (since Integer is assignable to Number) and returns the {@code @Deprecated} annotation
63 * incorrectly.</li>
64 * <li>Post-patch: uses getDeclaredMethod with exact types, finds nothing, returns null.</li>
65 * </ul>
66 */
67 @SuppressWarnings("javadoc")
68 @Test
69 public void testAnnotationLookupDoesNotMatchAssignableOverload() throws NoSuchMethodException {
70 final Method integerMethod = ProcessorImpl.class.getDeclaredMethod("process", Integer.class);
71 final Deprecated ann = MethodUtils.getAnnotation(integerMethod, Deprecated.class, true, true);
72 assertNull(ann, "process(Integer) is NOT an override of process(Number); its annotation lookup must return null");
73 final Method numberMethod = ProcessorImpl.class.getDeclaredMethod("process", Number.class);
74 assertNotNull(MethodUtils.getAnnotation(numberMethod, Deprecated.class, true, true));
75 }
76 }