Skip to content

Commit 04e69bd

Browse files
committed
Polish contribution
Closes gh-32412
1 parent 3e48031 commit 04e69bd

File tree

2 files changed

+87
-45
lines changed

2 files changed

+87
-45
lines changed

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.lang.reflect.Constructor;
2020
import java.lang.reflect.Method;
21-
import java.util.Objects;
2221

2322
import org.apache.commons.logging.Log;
2423
import org.apache.commons.logging.LogFactory;
@@ -289,10 +288,10 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp
289288
@Nullable
290289
private <T> T processReturnType(Method method, @Nullable T returnValue) {
291290
Class<?> returnType = method.getReturnType();
292-
if (returnType != void.class && returnType.isPrimitive()) {
293-
return Objects.requireNonNull(returnValue, () -> "Null return value from replacer does not match primitive return type for: " + method);
291+
if (returnValue == null && returnType != void.class && returnType.isPrimitive()) {
292+
throw new IllegalStateException(
293+
"Null return value from MethodReplacer does not match primitive return type for: " + method);
294294
}
295-
296295
return returnValue;
297296
}
298297
}
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,129 @@
1-
package org.springframework.beans.factory.support;
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
216

3-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
4-
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
17+
package org.springframework.beans.factory.support;
518

619
import java.lang.reflect.Method;
720
import java.util.Map;
21+
import java.util.regex.Pattern;
822
import java.util.stream.Stream;
923

10-
import org.assertj.core.api.ThrowableAssert;
24+
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
1125
import org.junit.jupiter.api.Test;
26+
1227
import org.springframework.lang.Nullable;
1328

29+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
30+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
31+
32+
/**
33+
* Tests for {@link CglibSubclassingInstantiationStrategy}.
34+
*
35+
* @author Mikaël Francoeur
36+
* @author Sam Brannen
37+
* @since 6.2
38+
*/
1439
class CglibSubclassingInstantiationStrategyTests {
1540

1641
private final CglibSubclassingInstantiationStrategy strategy = new CglibSubclassingInstantiationStrategy();
1742

18-
@Nullable
19-
public static Object valueToReturnFromReplacer;
2043

2144
@Test
22-
void methodOverride() {
45+
void replaceOverrideMethodInterceptorRejectsNullReturnValueForPrimitives() {
46+
MyReplacer replacer = new MyReplacer();
2347
StaticListableBeanFactory beanFactory = new StaticListableBeanFactory(Map.of(
2448
"myBean", new MyBean(),
25-
"replacer", new MyReplacer()
49+
"replacer", replacer
2650
));
2751

28-
RootBeanDefinition bd = new RootBeanDefinition(MyBean.class);
2952
MethodOverrides methodOverrides = new MethodOverrides();
30-
Stream.of("getBoolean", "getShort", "getInt", "getLong", "getFloat", "getDouble", "getByte")
31-
.forEach(methodToOverride -> addOverride(methodOverrides, methodToOverride));
53+
Stream.of("getBoolean", "getChar", "getByte", "getShort", "getInt", "getLong", "getFloat", "getDouble")
54+
.map(methodToOverride -> new ReplaceOverride(methodToOverride, "replacer"))
55+
.forEach(methodOverrides::addOverride);
56+
57+
RootBeanDefinition bd = new RootBeanDefinition(MyBean.class);
3258
bd.setMethodOverrides(methodOverrides);
3359

3460
MyBean bean = (MyBean) strategy.instantiate(bd, "myBean", beanFactory);
3561

36-
valueToReturnFromReplacer = null;
62+
replacer.reset();
3763
assertCorrectExceptionThrownBy(bean::getBoolean);
38-
valueToReturnFromReplacer = true;
64+
replacer.returnValue = true;
3965
assertThat(bean.getBoolean()).isTrue();
4066

41-
valueToReturnFromReplacer = null;
67+
replacer.reset();
68+
assertCorrectExceptionThrownBy(bean::getChar);
69+
replacer.returnValue = 'x';
70+
assertThat(bean.getChar()).isEqualTo('x');
71+
72+
replacer.reset();
73+
assertCorrectExceptionThrownBy(bean::getByte);
74+
replacer.returnValue = 123;
75+
assertThat(bean.getByte()).isEqualTo((byte) 123);
76+
77+
replacer.reset();
4278
assertCorrectExceptionThrownBy(bean::getShort);
43-
valueToReturnFromReplacer = 123;
79+
replacer.returnValue = 123;
4480
assertThat(bean.getShort()).isEqualTo((short) 123);
4581

46-
valueToReturnFromReplacer = null;
82+
replacer.reset();
4783
assertCorrectExceptionThrownBy(bean::getInt);
48-
valueToReturnFromReplacer = 123;
84+
replacer.returnValue = 123;
4985
assertThat(bean.getInt()).isEqualTo(123);
5086

51-
valueToReturnFromReplacer = null;
87+
replacer.reset();
5288
assertCorrectExceptionThrownBy(bean::getLong);
53-
valueToReturnFromReplacer = 123;
89+
replacer.returnValue = 123;
5490
assertThat(bean.getLong()).isEqualTo(123L);
5591

56-
valueToReturnFromReplacer = null;
92+
replacer.reset();
5793
assertCorrectExceptionThrownBy(bean::getFloat);
58-
valueToReturnFromReplacer = 123;
94+
replacer.returnValue = 123;
5995
assertThat(bean.getFloat()).isEqualTo(123f);
6096

61-
valueToReturnFromReplacer = null;
97+
replacer.reset();
6298
assertCorrectExceptionThrownBy(bean::getDouble);
63-
valueToReturnFromReplacer = 123;
99+
replacer.returnValue = 123;
64100
assertThat(bean.getDouble()).isEqualTo(123d);
65-
66-
valueToReturnFromReplacer = null;
67-
assertCorrectExceptionThrownBy(bean::getByte);
68-
valueToReturnFromReplacer = 123;
69-
assertThat(bean.getByte()).isEqualTo((byte) 123);
70101
}
71102

72-
private void assertCorrectExceptionThrownBy(ThrowableAssert.ThrowingCallable runnable) {
73-
assertThatThrownBy(runnable)
74-
.isInstanceOf(NullPointerException.class)
75-
.hasMessageMatching("Null return value from replacer does not match primitive return type for: "
76-
+ "\\w+ org\\.springframework\\.beans\\.factory\\.support\\.CglibSubclassingInstantiationStrategyTests\\$MyBean\\.\\w+\\(\\)");
77-
}
78103

79-
private void addOverride(MethodOverrides methodOverrides, String methodToOverride) {
80-
methodOverrides.addOverride(new ReplaceOverride(methodToOverride, "replacer"));
104+
private static void assertCorrectExceptionThrownBy(ThrowingCallable runnable) {
105+
assertThatIllegalStateException()
106+
.isThrownBy(runnable)
107+
.withMessageMatching(
108+
"Null return value from MethodReplacer does not match primitive return type for: " +
109+
"\\w+ %s\\.\\w+\\(\\)".formatted(Pattern.quote(MyBean.class.getName())));
81110
}
82111

112+
83113
static class MyBean {
114+
84115
boolean getBoolean() {
85116
return true;
86117
}
87118

119+
char getChar() {
120+
return 'x';
121+
}
122+
123+
byte getByte() {
124+
return 123;
125+
}
126+
88127
short getShort() {
89128
return 123;
90129
}
@@ -104,17 +143,21 @@ float getFloat() {
104143
double getDouble() {
105144
return 123;
106145
}
107-
108-
byte getByte() {
109-
return 123;
110-
}
111146
}
112147

113148
static class MyReplacer implements MethodReplacer {
114149

150+
@Nullable
151+
Object returnValue;
152+
153+
void reset() {
154+
this.returnValue = null;
155+
}
156+
115157
@Override
116158
public Object reimplement(Object obj, Method method, Object[] args) {
117-
return CglibSubclassingInstantiationStrategyTests.valueToReturnFromReplacer;
159+
return this.returnValue;
118160
}
119161
}
162+
120163
}

0 commit comments

Comments
 (0)