Skip to content

Commit 0c5c310

Browse files
committed
ReflectiveMethodExecutor skips interface search (plus related polishing)
1 parent c66f9d8 commit 0c5c310

File tree

5 files changed

+39
-43
lines changed

5 files changed

+39
-43
lines changed

spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java

Lines changed: 8 additions & 8 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.
@@ -86,17 +86,11 @@ public int getOrder() {
8686
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
8787
}
8888

89-
@Nullable
90-
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
91-
ResolvableType resolvableType = ResolvableType.forClass(listenerType).as(ApplicationListener.class);
92-
return (resolvableType.hasGenerics() ? resolvableType.getGeneric() : null);
93-
}
9489

9590
@Nullable
9691
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
9792
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
98-
if (declaredEventType == null || declaredEventType.isAssignableFrom(
99-
ResolvableType.forClass(ApplicationEvent.class))) {
93+
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
10094
Class<?> targetClass = AopUtils.getTargetClass(listener);
10195
if (targetClass != listener.getClass()) {
10296
declaredEventType = resolveDeclaredEventType(targetClass);
@@ -105,4 +99,10 @@ private static ResolvableType resolveDeclaredEventType(ApplicationListener<Appli
10599
return declaredEventType;
106100
}
107101

102+
@Nullable
103+
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
104+
ResolvableType resolvableType = ResolvableType.forClass(listenerType).as(ApplicationListener.class);
105+
return (resolvableType.hasGenerics() ? resolvableType.getGeneric() : null);
106+
}
107+
108108
}

spring-core/src/main/java/org/springframework/util/ClassUtils.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader
227227
* @param name the name of the Class
228228
* @param classLoader the class loader to use
229229
* (may be {@code null}, which indicates the default class loader)
230-
* @return Class instance for the supplied name
230+
* @return a class instance for the supplied name
231231
* @throws ClassNotFoundException if the class was not found
232232
* @throws LinkageError if the class file could not be loaded
233233
* @see Class#forName(String, boolean, ClassLoader)
@@ -298,7 +298,7 @@ public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
298298
* @param className the name of the Class
299299
* @param classLoader the class loader to use
300300
* (may be {@code null}, which indicates the default class loader)
301-
* @return Class instance for the supplied name
301+
* @return a class instance for the supplied name
302302
* @throws IllegalArgumentException if the class name was not resolvable
303303
* (that is, the class could not be found or the class file could not be loaded)
304304
* @see #forName(String, ClassLoader)
@@ -868,7 +868,7 @@ public static Class<?> getUserClass(Object instance) {
868868
public static Class<?> getUserClass(Class<?> clazz) {
869869
if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
870870
Class<?> superclass = clazz.getSuperclass();
871-
if (superclass != null && Object.class != superclass) {
871+
if (superclass != null && superclass != Object.class) {
872872
return superclass;
873873
}
874874
}
@@ -1227,10 +1227,10 @@ public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, String methodN
12271227
* access (e.g. calls to {@code Class#getDeclaredMethods} etc, this implementation
12281228
* will fall back to returning the originally provided method.
12291229
* @param method the method to be invoked, which may come from an interface
1230-
* @param targetClass the target class for the current invocation.
1231-
* May be {@code null} or may not even implement the method.
1230+
* @param targetClass the target class for the current invocation
1231+
* (may be {@code null} or may not even implement the method)
12321232
* @return the specific target method, or the original method if the
1233-
* {@code targetClass} doesn't implement it or is {@code null}
1233+
* {@code targetClass} does not implement it
12341234
*/
12351235
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
12361236
if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) {

spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,7 @@ private MethodExecutor getCachedExecutor(EvaluationContext evaluationContext, Ob
182182
@Nullable TypeDescriptor target, List<TypeDescriptor> argumentTypes) {
183183

184184
List<MethodResolver> methodResolvers = evaluationContext.getMethodResolvers();
185-
if (methodResolvers.size() != 1 ||
186-
!(methodResolvers.get(0) instanceof ReflectiveMethodResolver)) {
185+
if (methodResolvers.size() != 1 || !(methodResolvers.get(0) instanceof ReflectiveMethodResolver)) {
187186
// Not a default ReflectiveMethodResolver - don't know whether caching is valid
188187
return null;
189188
}
@@ -249,7 +248,7 @@ private void updateExitTypeDescriptor() {
249248
Method method = ((ReflectiveMethodExecutor) executorToCheck.get()).getMethod();
250249
String descriptor = CodeFlow.toDescriptor(method.getReturnType());
251250
if (this.nullSafe && CodeFlow.isPrimitive(descriptor)) {
252-
originalPrimitiveExitTypeDescriptor = descriptor;
251+
this.originalPrimitiveExitTypeDescriptor = descriptor;
253252
this.exitTypeDescriptor = CodeFlow.toBoxedDescriptor(descriptor);
254253
}
255254
else {
@@ -301,7 +300,7 @@ public boolean isCompilable() {
301300

302301
return true;
303302
}
304-
303+
305304
@Override
306305
public void generateCode(MethodVisitor mv, CodeFlow cf) {
307306
CachedMethodExecutor executorToCheck = this.cachedExecutor;
@@ -332,7 +331,7 @@ public void generateCode(MethodVisitor mv, CodeFlow cf) {
332331
// Something on the stack when nothing is needed
333332
mv.visitInsn(POP);
334333
}
335-
334+
336335
if (CodeFlow.isPrimitive(descriptor)) {
337336
CodeFlow.insertBoxIfNecessary(mv, descriptor.charAt(0));
338337
}

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java

Lines changed: 17 additions & 11 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.
@@ -29,6 +29,8 @@
2929
import org.springframework.util.ReflectionUtils;
3030

3131
/**
32+
* {@link MethodExecutor} that works via reflection.
33+
*
3234
* @author Andy Clement
3335
* @author Juergen Hoeller
3436
* @since 3.0
@@ -48,6 +50,10 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
4850
private boolean argumentConversionOccurred = false;
4951

5052

53+
/**
54+
* Create a new executor for the given method.
55+
* @param method the method to invoke
56+
*/
5157
public ReflectiveMethodExecutor(Method method) {
5258
this.method = method;
5359
if (method.isVarArgs()) {
@@ -60,6 +66,9 @@ public ReflectiveMethodExecutor(Method method) {
6066
}
6167

6268

69+
/**
70+
* Return the original method that this executor has been configured for.
71+
*/
6372
public Method getMethod() {
6473
return this.method;
6574
}
@@ -68,21 +77,22 @@ public Method getMethod() {
6877
* Find the first public class in the methods declaring class hierarchy that declares this method.
6978
* Sometimes the reflective method discovery logic finds a suitable method that can easily be
7079
* called via reflection but cannot be called from generated code when compiling the expression
71-
* because of visibility restrictions. For example if a non public class overrides toString(), this
72-
* helper method will walk up the type hierarchy to find the first public type that declares the
73-
* method (if there is one!). For toString() it may walk as far as Object.
80+
* because of visibility restrictions. For example if a non-public class overrides toString(),
81+
* this helper method will walk up the type hierarchy to find the first public type that declares
82+
* the method (if there is one!). For toString() it may walk as far as Object.
7483
*/
7584
@Nullable
7685
public Class<?> getPublicDeclaringClass() {
7786
if (!this.computedPublicDeclaringClass) {
78-
this.publicDeclaringClass = discoverPublicClass(this.method, this.method.getDeclaringClass());
87+
this.publicDeclaringClass =
88+
discoverPublicDeclaringClass(this.method, this.method.getDeclaringClass());
7989
this.computedPublicDeclaringClass = true;
8090
}
8191
return this.publicDeclaringClass;
8292
}
8393

8494
@Nullable
85-
private Class<?> discoverPublicClass(Method method, Class<?> clazz) {
95+
private Class<?> discoverPublicDeclaringClass(Method method, Class<?> clazz) {
8696
if (Modifier.isPublic(clazz.getModifiers())) {
8797
try {
8898
clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
@@ -92,12 +102,8 @@ private Class<?> discoverPublicClass(Method method, Class<?> clazz) {
92102
// Continue below...
93103
}
94104
}
95-
Class<?>[] ifcs = clazz.getInterfaces();
96-
for (Class<?> ifc: ifcs) {
97-
discoverPublicClass(method, ifc);
98-
}
99105
if (clazz.getSuperclass() != null) {
100-
return discoverPublicClass(method, clazz.getSuperclass());
106+
return discoverPublicDeclaringClass(method, clazz.getSuperclass());
101107
}
102108
return null;
103109
}

spring-expression/src/test/java/org/springframework/expression/spel/CachedMethodExecutorTests.java

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 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.
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.expression.spel;
1818

19-
import org.junit.Before;
2019
import org.junit.Test;
2120

2221
import org.springframework.expression.Expression;
@@ -36,17 +35,11 @@ public class CachedMethodExecutorTests {
3635

3736
private final ExpressionParser parser = new SpelExpressionParser();
3837

39-
private StandardEvaluationContext context;
40-
41-
42-
@Before
43-
public void setUp() throws Exception {
44-
this.context = new StandardEvaluationContext(new RootObject());
45-
}
38+
private final StandardEvaluationContext context = new StandardEvaluationContext(new RootObject());
4639

4740

4841
@Test
49-
public void testCachedExecutionForParameters() throws Exception {
42+
public void testCachedExecutionForParameters() {
5043
Expression expression = this.parser.parseExpression("echo(#var)");
5144

5245
assertMethodExecution(expression, 42, "int: 42");
@@ -56,7 +49,7 @@ public void testCachedExecutionForParameters() throws Exception {
5649
}
5750

5851
@Test
59-
public void testCachedExecutionForTarget() throws Exception {
52+
public void testCachedExecutionForTarget() {
6053
Expression expression = this.parser.parseExpression("#var.echo(42)");
6154

6255
assertMethodExecution(expression, new RootObject(), "int: 42");
@@ -76,15 +69,13 @@ public static class BaseObject {
7669
public String echo(String value) {
7770
return "String: " + value;
7871
}
79-
8072
}
8173

8274
public static class RootObject extends BaseObject {
8375

8476
public String echo(int value) {
8577
return "int: " + value;
8678
}
87-
8879
}
8980

9081
}

0 commit comments

Comments
 (0)