Skip to content

Commit 53d0139

Browse files
committed
Workaround for inner class constructor parameter annotation bug in javac
Issue: SPR-16652
1 parent 3ac46da commit 53d0139

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

spring-core/src/main/java/org/springframework/core/MethodParameter.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.lang.reflect.Executable;
2323
import java.lang.reflect.Member;
2424
import java.lang.reflect.Method;
25+
import java.lang.reflect.Modifier;
2526
import java.lang.reflect.Parameter;
2627
import java.lang.reflect.ParameterizedType;
2728
import java.lang.reflect.Type;
@@ -57,6 +58,8 @@
5758
*/
5859
public class MethodParameter {
5960

61+
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
62+
6063
private final Executable executable;
6164

6265
private final int parameterIndex;
@@ -514,11 +517,20 @@ public Annotation[] getParameterAnnotations() {
514517
Annotation[] paramAnns = this.parameterAnnotations;
515518
if (paramAnns == null) {
516519
Annotation[][] annotationArray = this.executable.getParameterAnnotations();
517-
if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) {
518-
paramAnns = adaptAnnotationArray(annotationArray[this.parameterIndex]);
520+
int index = this.parameterIndex;
521+
if (this.executable instanceof Constructor &&
522+
this.executable.getDeclaringClass().isMemberClass() &&
523+
!Modifier.isStatic(this.executable.getDeclaringClass().getModifiers()) &&
524+
annotationArray.length == this.executable.getParameterCount() - 1) {
525+
// Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
526+
// for inner classes, so access it with the actual parameter index lowered by 1
527+
index = this.parameterIndex - 1;
528+
}
529+
if (index >= 0 && index < annotationArray.length) {
530+
paramAnns = adaptAnnotationArray(annotationArray[index]);
519531
}
520532
else {
521-
paramAnns = new Annotation[0];
533+
paramAnns = EMPTY_ANNOTATION_ARRAY;
522534
}
523535
this.parameterAnnotations = paramAnns;
524536
}

spring-core/src/test/java/org/springframework/core/MethodParameterTests.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.lang.reflect.Method;
2525

2626
import org.junit.Before;
27-
import org.junit.Ignore;
2827
import org.junit.Test;
2928

3029
import static org.junit.Assert.*;
@@ -46,7 +45,7 @@ public class MethodParameterTests {
4645

4746

4847
@Before
49-
public void setUp() throws NoSuchMethodException {
48+
public void setup() throws NoSuchMethodException {
5049
method = getClass().getMethod("method", String.class, Long.TYPE);
5150
stringParameter = new MethodParameter(method, 0);
5251
longParameter = new MethodParameter(method, 1);
@@ -114,15 +113,22 @@ public void annotatedConstructorParameterInStaticNestedClass() throws Exception
114113
assertNotNull(methodParameter.getParameterAnnotation(Param.class));
115114
}
116115

117-
@Test
118-
@Ignore("Disabled until SPR-16652 is resolved")
116+
@Test // SPR-16652
119117
public void annotatedConstructorParameterInInnerClass() throws Exception {
120-
Constructor<?> constructor = InnerClass.class.getDeclaredConstructor(getClass(), String.class);
121-
MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 1);
118+
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Integer.class);
119+
120+
MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0);
121+
assertEquals(getClass(), methodParameter.getParameterType());
122+
assertNull(methodParameter.getParameterAnnotation(Param.class));
123+
124+
methodParameter = MethodParameter.forExecutable(constructor, 1);
122125
assertEquals(String.class, methodParameter.getParameterType());
123-
assertNull(methodParameter.getParameterAnnotation(Override.class));
124126
// The following assertion currently fails if this test class is compiled using JDK 8.
125127
assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class));
128+
129+
methodParameter = MethodParameter.forExecutable(constructor, 2);
130+
assertEquals(Integer.class, methodParameter.getParameterType());
131+
assertNull(methodParameter.getParameterAnnotation(Param.class));
126132
}
127133

128134

@@ -140,7 +146,7 @@ private static class NestedClass {
140146
@SuppressWarnings("unused")
141147
private class InnerClass {
142148

143-
InnerClass(@Param String s) {
149+
public InnerClass(@Param String s, Integer i) {
144150
}
145151
}
146152

0 commit comments

Comments
 (0)