Skip to content

Commit 50177b1

Browse files
committed
Refine CachedIntrospectionResults property introspection
Closes gh-28445
1 parent 159a99b commit 50177b1

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

Diff for: spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

+15-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.beans.IntrospectionException;
2121
import java.beans.Introspector;
2222
import java.beans.PropertyDescriptor;
23+
import java.net.URL;
2324
import java.security.ProtectionDomain;
2425
import java.util.Collections;
2526
import java.util.LinkedHashMap;
@@ -287,10 +288,12 @@ private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
287288
// Only allow all name variants of Class properties
288289
continue;
289290
}
290-
if (pd.getWriteMethod() == null && pd.getPropertyType() != null &&
291-
(ClassLoader.class.isAssignableFrom(pd.getPropertyType()) ||
292-
ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
293-
// Ignore ClassLoader and ProtectionDomain read-only properties - no need to bind to those
291+
if (URL.class == beanClass && "content".equals(pd.getName())) {
292+
// Only allow URL attribute introspection, not content resolution
293+
continue;
294+
}
295+
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
296+
// Ignore read-only properties such as ClassLoader - no need to bind to those
294297
continue;
295298
}
296299
if (logger.isTraceEnabled()) {
@@ -328,10 +331,8 @@ private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws
328331
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
329332
// against a declared read method, so we prefer read method descriptors here.
330333
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
331-
if (pd.getWriteMethod() == null && pd.getPropertyType() != null &&
332-
(ClassLoader.class.isAssignableFrom(pd.getPropertyType()) ||
333-
ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
334-
// Ignore ClassLoader and ProtectionDomain read-only properties - no need to bind to those
334+
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
335+
// Ignore read-only properties such as ClassLoader - no need to bind to those
335336
continue;
336337
}
337338
this.propertyDescriptors.put(pd.getName(), pd);
@@ -342,6 +343,12 @@ private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws
342343
}
343344
}
344345

346+
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
347+
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
348+
ClassLoader.class.isAssignableFrom(returnType) ||
349+
ProtectionDomain.class.isAssignableFrom(returnType)));
350+
}
351+
345352

346353
BeanInfo getBeanInfo() {
347354
return this.beanInfo;

Diff for: spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.beans.testfixture.beans.TestBean;
2626
import org.springframework.core.OverridingClassLoader;
2727
import org.springframework.core.io.DefaultResourceLoader;
28+
import org.springframework.core.io.UrlResource;
2829

2930
import static org.assertj.core.api.Assertions.assertThat;
3031
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -152,7 +153,7 @@ public void setPropertyTypeMismatch() {
152153
}
153154

154155
@Test
155-
public void propertyDescriptors() {
156+
public void propertyDescriptors() throws Exception {
156157
TestBean target = new TestBean();
157158
target.setSpouse(new TestBean());
158159
BeanWrapper accessor = createAccessor(target);
@@ -181,11 +182,29 @@ public void propertyDescriptors() {
181182
assertThat(accessor.isReadableProperty("class.package")).isFalse();
182183
assertThat(accessor.isReadableProperty("class.module")).isFalse();
183184
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
185+
assertThat(accessor.isReadableProperty("class.name")).isTrue();
186+
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
184187
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
185188
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
186189
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
187190
accessor.setPropertyValue("classLoader", ocl);
188191
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
192+
193+
accessor = createAccessor(new UrlResource("https://spring.io"));
194+
195+
assertThat(accessor.isReadableProperty("class.package")).isFalse();
196+
assertThat(accessor.isReadableProperty("class.module")).isFalse();
197+
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
198+
assertThat(accessor.isReadableProperty("class.name")).isTrue();
199+
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
200+
assertThat(accessor.isReadableProperty("URL.protocol")).isTrue();
201+
assertThat(accessor.isReadableProperty("URL.host")).isTrue();
202+
assertThat(accessor.isReadableProperty("URL.port")).isTrue();
203+
assertThat(accessor.isReadableProperty("URL.file")).isTrue();
204+
assertThat(accessor.isReadableProperty("URL.content")).isFalse();
205+
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
206+
assertThat(accessor.isReadableProperty("filename")).isTrue();
207+
assertThat(accessor.isReadableProperty("description")).isTrue();
189208
}
190209

191210
@Test

0 commit comments

Comments
 (0)