Skip to content

CachedIntrospectionResults should build complete descriptor for setter/getter across interface hierarchy [SPR-16978] #21516

Closed
@spring-projects-issues

Description

@spring-projects-issues

Petar Tahchiev opened SPR-16978 and commented

Hello,
consider the following setup:

// code from spring-security
public interface UserDetails extends Serializable {
  Collection<? extends GrantedAuthority> getAuthorities();

  String getPassword();

  String getUsername();

  boolean isAccountNonExpired();

  boolean isAccountNonLocked();

  boolean isCredentialsNonExpired();

  boolean isEnabled();
}

public interface MyUserDetails extends UserDetails {
    Locale getLocale();

    void setLocale(final Locale locale);

    /* setters for super properties */

    void setUsername(String username);

    void setPassword(String password);
}

public interface CustomerDetails extends MyUsersDetails {
  String getPhone();

  void setPhone(String phone);
}

Now invoke BeanUtils.getPropertyDescriptor(CustomerDetails.class, "username"); and you will see that the returned PropertyDescriptor has correct writeMethod but the readMethod is null. As a result, if I try to submit a CustomerDetails form in spring-mvc
I get this error:

2018-06-26 18:13:33,604 org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/storefront].[dispatcherServlet] [https-jsse-nio-127.0.0.1-8112-exec-5] ERROR: Servlet.service() for servlet [dispatcherServlet] in context with path [/storefront] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Method must not be null] with root cause
java.lang.IllegalArgumentException: Method must not be null
	at org.springframework.util.Assert.notNull(Assert.java:193)
	at org.springframework.core.MethodParameter.<init>(MethodParameter.java:120)
	at org.springframework.core.MethodParameter.<init>(MethodParameter.java:106)
	at org.springframework.data.web.MapDataBinder$MapPropertyAccessor.setPropertyValue(MapDataBinder.java:193)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValue(AbstractPropertyAccessor.java:67)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97)
	at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:839)
	at org.springframework.validation.DataBinder.doBind(DataBinder.java:735)
	at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197)
	at org.springframework.validation.DataBinder.bind(DataBinder.java:720

I believe this is because in CachedIntrospectionResults a look goes through all super interfaces:

while (clazz != null && clazz != Object.class) {
     Class<?>[] ifcs = clazz.getInterfaces();
     for (Class<?> ifc : ifcs) {
              if (!ClassUtils.isJavaLanguageInterface(ifc)) {
                       for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {

until Object is reached and for each finds the property descriptor. However when it reaches MyUserDetails it finds the setter method and creates a PropertyDescriptor with null read method which is wrong because the read method is defined in the parent interface.


Affects: 5.0.7

Issue Links:

Referenced from: commits bf5fe46

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions