Skip to content

Commit fee05e0

Browse files
committed
Harden candidate checks in bean context
Add defensive null handling and stricter filtering in `ConfigurationPropertiesBeanContext`: `isCandidateProperty` now rejects null descriptors and properties without a read method, and `isCandidateClass` now rejects null classes. Tests were updated to cover these edge cases and verify expected behavior for primitives, wrappers, enums, JDK types, and valid configuration properties.
1 parent 30f609f commit fee05e0

3 files changed

Lines changed: 37 additions & 5 deletions

File tree

microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContext.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,14 @@ static String buildPropertyPath(String propertyName, @Nullable String nestedPath
544544
* @return {@code true} if the property is a binding candidate, {@code false} otherwise
545545
*/
546546
static boolean isCandidateProperty(PropertyDescriptor descriptor) {
547+
if (descriptor == null) {
548+
return false;
549+
}
547550
Method readMethod = descriptor.getReadMethod();
548-
return readMethod == null || !Object.class.equals(readMethod.getDeclaringClass());
551+
if (readMethod == null) {
552+
return false;
553+
}
554+
return !Object.class.equals(readMethod.getDeclaringClass());
549555
}
550556

551557
/**
@@ -563,6 +569,9 @@ static boolean isCandidateProperty(PropertyDescriptor descriptor) {
563569
* @return {@code true} if the class is a binding candidate, {@code false} otherwise
564570
*/
565571
static boolean isCandidateClass(Class<?> beanClass) {
572+
if (beanClass == null) {
573+
return false;
574+
}
566575
if (isPrimitiveOrWrapper(beanClass) || beanClass.isEnum()) {
567576
return false;
568577
}

microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/EventPublishingConfigurationPropertiesBeanPropertyChangedListener.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@
5050
* @see ConfigurationPropertiesBeanPropertyChangedEvent
5151
* @since 1.0.0
5252
*/
53-
public class EventPublishingConfigurationPropertiesBeanPropertyChangedListener implements BindListener,
54-
ApplicationContextAware, InitializingBean, SmartInitializingSingleton {
53+
public class EventPublishingConfigurationPropertiesBeanPropertyChangedListener implements BindListener, ApplicationContextAware, InitializingBean, SmartInitializingSingleton {
5554

5655
private static final Logger logger = getLogger(EventPublishingConfigurationPropertiesBeanPropertyChangedListener.class);
5756

@@ -190,4 +189,4 @@ public void afterSingletonsInstantiated() {
190189
public boolean isBound() {
191190
return bound;
192191
}
193-
}
192+
}

microsphere-spring-boot-core/src/test/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContextTest.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
import org.springframework.core.annotation.AnnotationAttributes;
3232

3333
import java.beans.PropertyDescriptor;
34+
import java.util.concurrent.TimeUnit;
3435

3536
import static io.microsphere.spring.boot.context.properties.bind.ConfigurationPropertiesBeanContext.getInstance;
37+
import static io.microsphere.spring.boot.context.properties.bind.ConfigurationPropertiesBeanContext.isCandidateClass;
3638
import static io.microsphere.spring.boot.context.properties.bind.ConfigurationPropertiesBeanContext.isCandidateProperty;
3739
import static io.microsphere.spring.core.annotation.AnnotationUtils.getAnnotationAttributes;
3840
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -144,11 +146,33 @@ void testGetInstance() {
144146

145147
@Test
146148
void testIsCandidateProperty() {
149+
assertFalse(isCandidateProperty(null));
147150
PropertyDescriptor descriptor = getPropertyDescriptor(ConfigurationPropertiesBeanContextTest.class, "name");
148-
assertTrue(isCandidateProperty(descriptor));
151+
assertFalse(isCandidateProperty(descriptor));
152+
153+
descriptor = getPropertyDescriptor(ConfigurationPropertiesBeanContextTest.class, "not-found");
154+
assertFalse(isCandidateProperty(descriptor));
149155

150156
descriptor = getPropertyDescriptor(ConfigurationPropertiesBeanContextTest.class, "class");
151157
assertFalse(isCandidateProperty(descriptor));
158+
159+
descriptor = getPropertyDescriptor(ServerProperties.class, "port");
160+
assertTrue(isCandidateProperty(descriptor));
161+
}
162+
163+
@Test
164+
void testIsCandidateClass() {
165+
// null
166+
assertFalse(isCandidateClass(null));
167+
// primitive type and wrapper type are not candidate class
168+
assertFalse(isCandidateClass(int.class));
169+
assertFalse(isCandidateClass(Integer.class));
170+
// enumeration type
171+
assertFalse(isCandidateClass(TimeUnit.class));
172+
// String is candidate class,but is under java.lang package.
173+
assertFalse(isCandidateClass(String.class));
174+
// current class
175+
assertTrue(isCandidateClass(getClass()));
152176
}
153177

154178
public void setName(String name) {

0 commit comments

Comments
 (0)