I had a simple field like pId
, and it can used in jpa repository like :
List<Company> findByPId(Integer pid);
It can work When I import:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
Then I update the project level now:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.13.RELEASE</version>
</dependency>
But It can't work anymore. Here is startup error message:
Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [PId] on this ManagedType [a.Company]
at org.hibernate.metamodel.internal.AbstractManagedType.checkNotNull(AbstractManagedType.java:128)
at org.hibernate.metamodel.internal.AbstractManagedType.getAttribute(AbstractManagedType.java:113)
at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:634)
at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:618)
at org.springframework.data.jpa.repository.query.JpaQueryCreator$PredicateBuilder.getTypedPath(JpaQueryCreator.java:384)
at org.springframework.data.jpa.repository.query.JpaQueryCreator$PredicateBuilder.build(JpaQueryCreator.java:276)
at org.springframework.data.jpa.repository.query.JpaQueryCreator.toPredicate(JpaQueryCreator.java:210)
at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:123)
at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:58)
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:119)
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:95)
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:81)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.<init>(PartTreeJpaQuery.java:147)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$CountQueryPreparer.<init>(PartTreeJpaQuery.java:270)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:79)
... 70 common frames omitted
- Question How can i use like it again? Or should I add some properties?
Comment From: zero3h
I debug the source core and find something different bewteen 2.0.x and 2.1.x, here is core: - Jar: spring-data-commons-2.0.13.RELEASE.jar - Class: org.springframework.data.repository.query.parser.Part
public String extractProperty(String part) {
String candidate = StringUtils.uncapitalize(part);
for (String keyword : keywords) {
if (candidate.endsWith(keyword)) {
return candidate.substring(0, candidate.length() - keyword.length());
}
}
return candidate;
}
Tool Class: org.springframework.util.StringUtils
public static String uncapitalize(String str) {
return changeFirstCharacterCase(str, false);
}
private static String changeFirstCharacterCase(String str, boolean capitalize) {
if (!hasLength(str)) {
return str;
}
char baseChar = str.charAt(0);
char updatedChar;
if (capitalize) {
updatedChar = Character.toUpperCase(baseChar);
}
else {
updatedChar = Character.toLowerCase(baseChar);
}
if (baseChar == updatedChar) {
return str;
}
char[] chars = str.toCharArray();
chars[0] = updatedChar;
return new String(chars, 0, chars.length);
}
The updated version: - Jar: spring-data-commons-2.1.14.RELEASE.jar - Class: org.springframework.data.repository.query.parser.Part
public String extractProperty(String part) {
String candidate = Introspector.decapitalize(part);
for (String keyword : keywords) {
if (candidate.endsWith(keyword)) {
return candidate.substring(0, candidate.length() - keyword.length());
}
}
return candidate;
}
- Tool Class: java.beans.Introspector
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
So I think that's the problem.
I rewrite the class Part
to use StringUtils.uncapitalize(String str)
now, will it be fixed in a future version in 2.1.x?
Comment From: wilkinsona
@zero3h Thanks for the report and problem diagnosis. Spring Data Commons is managed as a separate project. The change was made to fix DATACMNS-1570. I believe you can avoid the problem by renaming the property or by adding a @Query
to the method. If you require any further guidance, please follow up with the Spring Data team on Gitter or Stack Overflow.