Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 56b082d

Browse files
committed
Merge branch '6.2.x'
2 parents b59fec2 + a6f6ecf commit 56b082d

File tree

5 files changed

+58
-21
lines changed

5 files changed

+58
-21
lines changed

‎spring-context/src/main/java/org/springframework/context/event/EventListener.java‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,9 @@
101101

102102
/**
103103
* The event classes that this listener handles.
104-
* <p>If this attribute is specified with a single value, the
105-
* annotated method may optionally accept a single parameter.
106-
* However, if this attribute is specified with multiple values,
107-
* the annotated method must <em>not</em> declare any parameters.
104+
* <p>The annotated method may optionally accept a single parameter
105+
* of the given event class, or of a common base class or interface
106+
* for all given event classes.
108107
*/
109108
@AliasFor("value")
110109
Class<?>[] classes() default {};

‎spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.context.event;
1818

19+
import java.io.Serializable;
1920
import java.lang.annotation.ElementType;
2021
import java.lang.annotation.Retention;
2122
import java.lang.annotation.RetentionPolicy;
@@ -105,8 +106,9 @@ void simpleEventJavaConfig() {
105106
this.eventCollector.assertTotalEventsCount(1);
106107

107108
this.eventCollector.clear();
108-
this.context.publishEvent(event);
109-
this.eventCollector.assertEvent(listener, event);
109+
TestEvent otherEvent = new TestEvent(this, Integer.valueOf(1));
110+
this.context.publishEvent(otherEvent);
111+
this.eventCollector.assertEvent(listener, otherEvent);
110112
this.eventCollector.assertTotalEventsCount(1);
111113

112114
context.getBean(ApplicationEventMulticaster.class).removeApplicationListeners(l ->
@@ -723,6 +725,11 @@ public void handle(TestEvent event) {
723725
public void handleString(String content) {
724726
collectEvent(content);
725727
}
728+
729+
@EventListener({Boolean.class, Integer.class})
730+
public void handleBooleanOrInteger(Serializable content) {
731+
collectEvent(content);
732+
}
726733
}
727734

728735

@@ -990,6 +997,8 @@ interface ConditionalEventInterface extends Identifiable {
990997

991998
void handleString(String payload);
992999

1000+
void handleBooleanOrInteger(Serializable content);
1001+
9931002
void handleTimestamp(Long timestamp);
9941003

9951004
void handleRatio(Double ratio);
@@ -1012,6 +1021,12 @@ public void handleString(String payload) {
10121021
super.handleString(payload);
10131022
}
10141023

1024+
@EventListener({Boolean.class, Integer.class})
1025+
@Override
1026+
public void handleBooleanOrInteger(Serializable content) {
1027+
super.handleBooleanOrInteger(content);
1028+
}
1029+
10151030
@ConditionalEvent("#root.event.timestamp > #p0")
10161031
@Override
10171032
public void handleTimestamp(Long timestamp) {

‎spring-context/src/test/java/org/springframework/context/event/test/TestEvent.java‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818

1919
/**
2020
* @author Stephane Nicoll
21+
* @author Juergen Hoeller
2122
*/
2223
@SuppressWarnings("serial")
2324
public class TestEvent extends IdentifiableApplicationEvent {
2425

25-
public final String msg;
26+
public final Object msg;
2627

2728
public TestEvent(Object source, String id, String msg) {
2829
super(source, id);
@@ -34,6 +35,11 @@ public TestEvent(Object source, String msg) {
3435
this.msg = msg;
3536
}
3637

38+
public TestEvent(Object source, Integer msg) {
39+
super(source);
40+
this.msg = msg;
41+
}
42+
3743
public TestEvent(Object source) {
3844
this(source, "test");
3945
}

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,8 @@ private static Method getInterfaceMethodIfPossible(Method method, @Nullable Clas
14661466
}
14671467

14681468
/**
1469-
* Get the highest publicly accessible method in the supplied method's type hierarchy that
1470-
* has a method signature equivalent to the supplied method, if possible.
1469+
* Get the closest publicly accessible (and exported) method in the supplied method's type
1470+
* hierarchy that has a method signature equivalent to the supplied method, if possible.
14711471
* <p>Otherwise, this method recursively searches the class hierarchy and implemented
14721472
* interfaces for an equivalent method that is {@code public} and declared in a
14731473
* {@code public} type.
@@ -1490,18 +1490,21 @@ private static Method getInterfaceMethodIfPossible(Method method, @Nullable Clas
14901490
* @see #getMostSpecificMethod(Method, Class)
14911491
*/
14921492
public static Method getPubliclyAccessibleMethodIfPossible(Method method, @Nullable Class<?> targetClass) {
1493-
// If the method is not public, we can abort the search immediately.
1494-
if (!Modifier.isPublic(method.getModifiers())) {
1493+
Class<?> declaringClass = method.getDeclaringClass();
1494+
// If the method is not public or its declaring class is public and exported already,
1495+
// we can abort the search immediately (avoiding reflection as well as cache access).
1496+
if (!Modifier.isPublic(method.getModifiers()) || (Modifier.isPublic(declaringClass.getModifiers()) &&
1497+
declaringClass.getModule().isExported(declaringClass.getPackageName(), ClassUtils.class.getModule()))) {
14951498
return method;
14961499
}
14971500

14981501
Method interfaceMethod = getInterfaceMethodIfPossible(method, targetClass, true);
14991502
// If we found a method in a public interface, return the interface method.
1500-
if (interfaceMethod != method) {
1503+
if (interfaceMethod != method && interfaceMethod.getDeclaringClass().getModule().isExported(
1504+
interfaceMethod.getDeclaringClass().getPackageName(), ClassUtils.class.getModule())) {
15011505
return interfaceMethod;
15021506
}
15031507

1504-
Class<?> declaringClass = method.getDeclaringClass();
15051508
// Bypass cache for java.lang.Object unless it is actually an overridable method declared there.
15061509
if (declaringClass.getSuperclass() == Object.class && !ReflectionUtils.isObjectMethod(method)) {
15071510
return method;
@@ -1522,7 +1525,9 @@ public static Method getPubliclyAccessibleMethodIfPossible(Method method, @Nulla
15221525
if (method == null) {
15231526
break;
15241527
}
1525-
if (Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
1528+
if (Modifier.isPublic(method.getDeclaringClass().getModifiers()) &&
1529+
method.getDeclaringClass().getModule().isExported(
1530+
method.getDeclaringClass().getPackageName(), ClassUtils.class.getModule())) {
15261531
result = method;
15271532
}
15281533
current = method.getDeclaringClass().getSuperclass();

‎spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.lang.reflect.Method;
2828
import java.lang.reflect.Modifier;
2929
import java.lang.reflect.Proxy;
30+
import java.net.URLConnection;
3031
import java.time.ZoneId;
3132
import java.util.ArrayList;
3233
import java.util.Arrays;
@@ -687,13 +688,13 @@ void publicMethodInNonPublicInterface() throws Exception {
687688
}
688689

689690
@Test
690-
void publicMethodInObjectClass() throws Exception {
691+
void publicMethodInPublicClass() throws Exception {
691692
Class<?> originalType = String.class;
692-
Method originalMethod = originalType.getDeclaredMethod("hashCode");
693+
Method originalMethod = originalType.getDeclaredMethod("toString");
693694

694695
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(originalMethod, null);
695-
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(Object.class);
696-
assertThat(publiclyAccessibleMethod.getName()).isEqualTo("hashCode");
696+
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(originalType);
697+
assertThat(publiclyAccessibleMethod).isSameAs(originalMethod);
697698
assertPubliclyAccessible(publiclyAccessibleMethod);
698699
}
699700

@@ -703,9 +704,20 @@ void publicInterfaceMethodInPublicClass() throws Exception {
703704
Method originalMethod = originalType.getDeclaredMethod("size");
704705

705706
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(originalMethod, null);
706-
// Should find the interface method in List.
707-
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(List.class);
708-
assertThat(publiclyAccessibleMethod.getName()).isEqualTo("size");
707+
// Should not find the interface method in List.
708+
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(originalType);
709+
assertThat(publiclyAccessibleMethod).isSameAs(originalMethod);
710+
assertPubliclyAccessible(publiclyAccessibleMethod);
711+
}
712+
713+
@Test
714+
void publicMethodInNonExportedClass() throws Exception {
715+
Class<?> originalType = getClass().getClassLoader().loadClass("sun.net.www.protocol.http.HttpURLConnection");
716+
Method originalMethod = originalType.getDeclaredMethod("getOutputStream");
717+
718+
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(originalMethod, null);
719+
assertThat(publiclyAccessibleMethod.getDeclaringClass()).isEqualTo(URLConnection.class);
720+
assertThat(publiclyAccessibleMethod.getName()).isSameAs(originalMethod.getName());
709721
assertPubliclyAccessible(publiclyAccessibleMethod);
710722
}
711723

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /