Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decapitalization of property names in repository queries breaks for properties with single lowercase letter followed by an uppercase letter [DATACMNS-1589] #2016

Closed
spring-projects-issues opened this issue Oct 9, 2019 · 3 comments
Assignees
Labels
in: repository status: declined

Comments

@spring-projects-issues
Copy link

@spring-projects-issues spring-projects-issues commented Oct 9, 2019

Andre Kupka opened DATACMNS-1589 and commented

The property resolution in custom repository queries fails if the property name starts with a single lowercase letter followed by an uppercase letter. The following entity and repository demonstrate the problem:

Entity

 

@Entity
@Table(name="customer")
public class Customer {

    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "c_login_id", nullable = false)
    private String cLoginId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCLoginId() {
        return cLoginId;
    }

    public void setCLoginId(String cLoginId) {
        this.cLoginId = cLoginId;
    }
}

Repository

 

@Repository
public interface CustomerRepository extends JpaRepository<Customer, String> {

    Optional<Customer> findByCLoginId(String cLoginId);
}

 

 

In Spring Boot version 2.1.8.RELEASE (includes spring-data-commons 2.1.10.RELEASE) the code above was working but in version 2.1.9.RELEASE (includes spring-data-commons 2.1.11.RELEASE) the following exception was thrown:

 

Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [CLoginId] on this ManagedType [de.andrekupka.demo.propertyresolution.Customer]
	at org.hibernate.metamodel.internal.AbstractManagedType.checkNotNull(AbstractManagedType.java:128) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
	at org.hibernate.metamodel.internal.AbstractManagedType.getAttribute(AbstractManagedType.java:113) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
	at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:633) ~[spring-data-jpa-2.1.11.RELEASE.jar:2.1.11.RELEASE]

 

 

I have implemented a minimal working example in https://github.com/andrekupka/jpa-property-name-resolution to reproduce the behavior and tagged a working, a broken and two workaround versions:

Working version: https://github.com/andrekupka/jpa-property-name-resolution/tree/working/2.1.8

Broken version: https://github.com/andrekupka/jpa-property-name-resolution/tree/not-working/2.1.9

Workaround with a custom Query annotation: https://github.com/andrekupka/jpa-property-name-resolution/tree/fix/query

Workaround by renaming the query method: https://github.com/andrekupka/jpa-property-name-resolution/tree/fix/property-renaming

The Testcase CustomerRepositoryTest can be used to reproduce the behavior.

 

The regression was introduced with PR #402 which uses https://docs.oracle.com/javase/7/docs/api/java/beans/Introspector.html#decapitalize(java.lang.String) for property decapitalization instead of Spring's own StringUtils class.

Tthe documentation at https://docs.spring.io/spring-data/data-commons/docs/current/reference/html/#repositories.query-methods.query-property-expressions does not mention the changed behavior as well. The documentation states that the first character of the property is decapitalized therefore the former example should still work.

Solution Proposal

I think using the decapitalization from the Java Bean Introspector is the correct behavior, thus the documentation should be updated and explicitly mention this special case.

 

 


Affects: 2.1.11 (Lovelace SR11)

Issue Links:

  • DATACMNS-1570 Parsing of query method names is inconsistent for attributes beginning with a single lower case character followed by an upper case character
@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Oct 10, 2019

Oliver Drotbohm commented

Looks like you're running into a side-effect of the fix for DATACMNS-1570. It might be surprising – it definitely is to me – but according to the Java Beans specification the expected getter method name is getcLoginId.

The documentation states that the first character of the property is decapitalized therefore the former example should still work.

Actually, I can't find that in the section you linked. We don't state any details except "uncapitalized" which I guess we can improve on by replacing it with "converted ac cording to the Java Beans specification"

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Oct 14, 2019

Andre Kupka commented

I was referring to the statement "... checks the domain class for a property with that name (uncapitalized).". I have interpreted the word "uncapitalized" as "the first character of the property is decapitalized" which was the original behavior as well.

getcLoginId feels some kind of weird although adhering to the Java Beans specification is the correct way IMO.

I would appreciate if you would explicitly mention this detail in the linked documentation, as this would have helped a lot in the first place

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Apr 6, 2020

Jens Schauder commented

As described by Oliver the current behavior is intentionally consistent with the Java Beans Specification. We are actually using java.beans.Introspector

I'm therefore closing this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: repository status: declined
Projects
None yet
Development

No branches or pull requests

2 participants