Refine CachedIntrospectionResults property introspection
Closes gh-28445
This commit is contained in:
parent
dc2947c52d
commit
83186b689f
|
|
@ -22,6 +22,7 @@ import java.beans.Introspector;
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.URL;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
@ -292,10 +293,12 @@ public final class CachedIntrospectionResults {
|
||||||
// Only allow all name variants of Class properties
|
// Only allow all name variants of Class properties
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pd.getWriteMethod() == null && pd.getPropertyType() != null &&
|
if (URL.class == beanClass && "content".equals(pd.getName())) {
|
||||||
(ClassLoader.class.isAssignableFrom(pd.getPropertyType()) ||
|
// Only allow URL attribute introspection, not content resolution
|
||||||
ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
|
continue;
|
||||||
// Ignore ClassLoader and ProtectionDomain read-only properties - no need to bind to those
|
}
|
||||||
|
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
|
||||||
|
// Ignore read-only properties such as ClassLoader - no need to bind to those
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
|
|
@ -344,10 +347,8 @@ public final class CachedIntrospectionResults {
|
||||||
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
|
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
|
||||||
// against a declared read method, so we prefer read method descriptors here.
|
// against a declared read method, so we prefer read method descriptors here.
|
||||||
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
|
||||||
if (pd.getWriteMethod() == null && pd.getPropertyType() != null &&
|
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
|
||||||
(ClassLoader.class.isAssignableFrom(pd.getPropertyType()) ||
|
// Ignore read-only properties such as ClassLoader - no need to bind to those
|
||||||
ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
|
|
||||||
// Ignore ClassLoader and ProtectionDomain read-only properties - no need to bind to those
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this.propertyDescriptors.put(pd.getName(), pd);
|
this.propertyDescriptors.put(pd.getName(), pd);
|
||||||
|
|
@ -379,8 +380,7 @@ public final class CachedIntrospectionResults {
|
||||||
if (Modifier.isStatic(method.getModifiers()) ||
|
if (Modifier.isStatic(method.getModifiers()) ||
|
||||||
method.getDeclaringClass() == Object.class || method.getDeclaringClass() == Class.class ||
|
method.getDeclaringClass() == Object.class || method.getDeclaringClass() == Class.class ||
|
||||||
method.getParameterCount() > 0 || method.getReturnType() == void.class ||
|
method.getParameterCount() > 0 || method.getReturnType() == void.class ||
|
||||||
ClassLoader.class.isAssignableFrom(method.getReturnType()) ||
|
isInvalidReadOnlyPropertyType(method.getReturnType())) {
|
||||||
ProtectionDomain.class.isAssignableFrom(method.getReturnType())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
@ -393,6 +393,12 @@ public final class CachedIntrospectionResults {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
|
||||||
|
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
|
||||||
|
ClassLoader.class.isAssignableFrom(returnType) ||
|
||||||
|
ProtectionDomain.class.isAssignableFrom(returnType)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BeanInfo getBeanInfo() {
|
BeanInfo getBeanInfo() {
|
||||||
return this.beanInfo;
|
return this.beanInfo;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.testfixture.beans.TestBean;
|
import org.springframework.beans.testfixture.beans.TestBean;
|
||||||
import org.springframework.core.OverridingClassLoader;
|
import org.springframework.core.OverridingClassLoader;
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
@ -153,7 +154,7 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void propertyDescriptors() {
|
void propertyDescriptors() throws Exception {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
target.setSpouse(new TestBean());
|
target.setSpouse(new TestBean());
|
||||||
BeanWrapper accessor = createAccessor(target);
|
BeanWrapper accessor = createAccessor(target);
|
||||||
|
|
@ -182,11 +183,29 @@ class BeanWrapperTests extends AbstractPropertyAccessorTests {
|
||||||
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
||||||
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
||||||
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("class.name")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
|
||||||
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
|
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
|
||||||
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
|
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
|
||||||
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
|
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
|
||||||
accessor.setPropertyValue("classLoader", ocl);
|
accessor.setPropertyValue("classLoader", ocl);
|
||||||
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
|
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
|
||||||
|
|
||||||
|
accessor = createAccessor(new UrlResource("https://spring.io"));
|
||||||
|
|
||||||
|
assertThat(accessor.isReadableProperty("class.package")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("class.module")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("class.name")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("URL.protocol")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("URL.host")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("URL.port")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("URL.file")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("URL.content")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
|
||||||
|
assertThat(accessor.isReadableProperty("filename")).isTrue();
|
||||||
|
assertThat(accessor.isReadableProperty("description")).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue