Skip to content

Commit b6d83ed

Browse files
committed
8371960: Missing null check in AnnotatedType annotation accessor methods
Reviewed-by: alanb
1 parent 43040f3 commit b6d83ed

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -128,7 +128,7 @@ private static class AnnotatedTypeBaseImpl implements AnnotatedType {
128128
private final Type type;
129129
private final LocationInfo location;
130130
private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
131-
private final Map<Class <? extends Annotation>, Annotation> annotations;
131+
private final Map<Class<? extends Annotation>, Annotation> annotations;
132132

133133
AnnotatedTypeBaseImpl(Type type, LocationInfo location,
134134
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations) {
@@ -162,11 +162,13 @@ public final Annotation[] getDeclaredAnnotations() {
162162
@Override
163163
@SuppressWarnings("unchecked")
164164
public final <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
165+
Objects.requireNonNull(annotation);
165166
return (T)annotations.get(annotation);
166167
}
167168

168169
@Override
169170
public final <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotation) {
171+
Objects.requireNonNull(annotation);
170172
return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation);
171173
}
172174

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8371953 8371960
27+
* @summary Null checks for AnnotatedElement APIs.
28+
* @run junit AnnotatedElementNullCheckTest
29+
*/
30+
31+
import java.lang.reflect.AnnotatedArrayType;
32+
import java.lang.reflect.AnnotatedElement;
33+
import java.lang.reflect.AnnotatedParameterizedType;
34+
import java.util.HashSet;
35+
import java.util.List;
36+
import java.util.Optional;
37+
import java.util.function.Consumer;
38+
39+
import org.junit.jupiter.api.Test;
40+
import org.junit.jupiter.params.ParameterizedTest;
41+
import org.junit.jupiter.params.provider.MethodSource;
42+
43+
import static org.junit.jupiter.api.Assertions.assertThrows;
44+
import static org.junit.jupiter.api.Assertions.fail;
45+
46+
class AnnotatedElementNullCheckTest {
47+
48+
// Return a stream of instances, each of a different implementation class
49+
static AnnotatedElement[] implementations() throws Exception {
50+
var objectHashCodeMethod = Object.class.getMethod("hashCode");
51+
var annotatedParameterizedType = (AnnotatedParameterizedType) Optional.class
52+
.getMethod("ifPresent", Consumer.class)
53+
.getAnnotatedParameterTypes()[0];
54+
var annotatedGenericArrayType = (AnnotatedArrayType) List.class
55+
.getMethod("of", Object[].class)
56+
.getAnnotatedParameterTypes()[0];
57+
record Rec(int a) {}
58+
return new AnnotatedElement[] {
59+
Object.class,
60+
objectHashCodeMethod,
61+
System.class.getField("out"),
62+
Object.class.getConstructor(),
63+
Object.class.getPackage(),
64+
Optional.class.getTypeParameters()[0],
65+
// AnnotatedType (direct)
66+
objectHashCodeMethod.getAnnotatedReturnType(),
67+
// AnnotatedParameterizedType
68+
annotatedParameterizedType,
69+
// AnnotatedArrayType
70+
annotatedGenericArrayType,
71+
// AnnotatedTypeVariable
72+
annotatedGenericArrayType.getAnnotatedGenericComponentType(),
73+
// AnnotatedWildcardType
74+
annotatedParameterizedType.getAnnotatedActualTypeArguments()[0],
75+
Rec.class.getRecordComponents()[0],
76+
Object.class.getMethod("equals", Object.class).getParameters()[0],
77+
Object.class.getModule(),
78+
};
79+
}
80+
81+
@Test
82+
void ensureImplementationsDistinct() throws Throwable {
83+
var set = new HashSet<Class<?>>();
84+
for (var impl : implementations()) {
85+
var clazz = impl.getClass();
86+
if (!set.add(clazz)) {
87+
fail("Duplicate implementation class %s in %s".formatted(clazz, impl));
88+
}
89+
}
90+
}
91+
92+
@ParameterizedTest
93+
@MethodSource("implementations")
94+
void nullChecks(AnnotatedElement impl) {
95+
assertThrows(NullPointerException.class, () -> impl.isAnnotationPresent(null));
96+
assertThrows(NullPointerException.class, () -> impl.getAnnotation(null));
97+
assertThrows(NullPointerException.class, () -> impl.getAnnotationsByType(null));
98+
assertThrows(NullPointerException.class, () -> impl.getDeclaredAnnotation(null));
99+
assertThrows(NullPointerException.class, () -> impl.getDeclaredAnnotationsByType(null));
100+
}
101+
}

0 commit comments

Comments
 (0)