Skip to content

Commit 225cd9b

Browse files
quaffchristophstrobl
authored andcommitted
Fallback to Path.getModel() if ManagedType information was erased.
ManagedType information may be erased if the attribute is declared as generic - With Hibernate 6.x for example an IllegalArgumentException is thrown. java.lang.IllegalArgumentException: Unable to locate Attribute with the given name [name] on this ManagedType [java.lang.Object] at o.h.m.model.domain.AbstractManagedType.checkNotNull(AbstractManagedType.java:225) ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final] Resolves: #3274 Original Pull Request: #3375
1 parent 314dc5c commit 225cd9b

File tree

9 files changed

+256
-1
lines changed

9 files changed

+256
-1
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
* @author Donghun Shin
9393
* @author Pranav HS
9494
* @author Eduard Dudar
95+
* @author Yanming Zhou
9596
*/
9697
public abstract class QueryUtils {
9798

@@ -844,7 +845,15 @@ private static boolean requiresOuterJoin(From<?, ?> from, PropertyPath property,
844845
managedType = (ManagedType<?>) ((SingularAttribute<?, ?>) model).getType();
845846
}
846847
if (managedType != null) {
847-
propertyPathModel = (Bindable<?>) managedType.getAttribute(segment);
848+
try {
849+
propertyPathModel = (Bindable<?>) managedType.getAttribute(segment);
850+
} catch (IllegalArgumentException ex) {
851+
// ManagedType may be erased type for some vendor if the attribute is declared as generic
852+
// see: https://hibernate.atlassian.net/browse/HHH-16144
853+
// see: https://github.com/hibernate/hibernate-orm/pull/7630
854+
// see: https://github.com/jakartaee/persistence/issues/562
855+
propertyPathModel = from.get(segment).getModel();
856+
}
848857
} else {
849858
propertyPathModel = from.get(segment).getModel();
850859
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2008-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.sample;
17+
18+
import jakarta.persistence.Entity;
19+
import jakarta.persistence.GeneratedValue;
20+
import jakarta.persistence.Id;
21+
import org.springframework.data.jpa.domain.AbstractPersistable;
22+
23+
/**
24+
* @author Yanming Zhou
25+
*/
26+
@Entity
27+
public class Book extends OwnerContainer<Owner> {
28+
29+
@Id
30+
@GeneratedValue
31+
private Long id;
32+
33+
public Long getId() {
34+
return id;
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2008-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.sample;
17+
18+
import jakarta.persistence.Entity;
19+
import org.springframework.data.jpa.domain.AbstractPersistable;
20+
21+
/**
22+
* @author Yanming Zhou
23+
*/
24+
@Entity
25+
public class Owner extends AbstractPersistable<Long> {
26+
27+
private String name;
28+
29+
public String getName() {
30+
return name;
31+
}
32+
33+
public void setName(String name) {
34+
this.name = name;
35+
}
36+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2008-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.domain.sample;
17+
18+
import jakarta.persistence.ManyToOne;
19+
import jakarta.persistence.MappedSuperclass;
20+
21+
/**
22+
* @author Yanming Zhou
23+
*/
24+
@MappedSuperclass
25+
public class OwnerContainer<T> {
26+
27+
@ManyToOne
28+
T owner;
29+
30+
public T getOwner() {
31+
return owner;
32+
}
33+
34+
public void setOwner(T owner) {
35+
this.owner = owner;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2014-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.repository.generics;
17+
18+
import jakarta.persistence.EntityManager;
19+
import org.junit.jupiter.api.BeforeEach;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.data.jpa.domain.sample.Book;
24+
import org.springframework.data.jpa.domain.sample.Owner;
25+
import org.springframework.data.jpa.repository.sample.BookRepository;
26+
import org.springframework.test.context.ContextConfiguration;
27+
import org.springframework.test.context.junit.jupiter.SpringExtension;
28+
import org.springframework.transaction.annotation.Transactional;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* @author Yanming Zhou
34+
*/
35+
@Transactional
36+
@ExtendWith(SpringExtension.class)
37+
@ContextConfiguration({ "classpath:eclipselink.xml", "classpath:config/namespace-application-context.xml" })
38+
class EclipseLinkGenericsIntegrationTests extends GenericsIntegrationTests {
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2014-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.repository.generics;
17+
18+
import jakarta.persistence.EntityManager;
19+
import org.junit.jupiter.api.BeforeEach;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.data.jpa.domain.AbstractPersistable;
24+
import org.springframework.data.jpa.domain.sample.Book;
25+
import org.springframework.data.jpa.domain.sample.CustomAbstractPersistable;
26+
import org.springframework.data.jpa.domain.sample.Owner;
27+
import org.springframework.data.jpa.repository.sample.BookRepository;
28+
import org.springframework.data.jpa.repository.sample.CustomAbstractPersistableRepository;
29+
import org.springframework.test.context.ContextConfiguration;
30+
import org.springframework.test.context.junit.jupiter.SpringExtension;
31+
import org.springframework.transaction.annotation.Transactional;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* @author Yanming Zhou
37+
*/
38+
@Transactional
39+
@ExtendWith(SpringExtension.class)
40+
@ContextConfiguration(locations = { "classpath:config/namespace-autoconfig-context.xml" })
41+
class GenericsIntegrationTests {
42+
43+
@Autowired
44+
BookRepository repository;
45+
46+
@Autowired
47+
EntityManager entityManager;
48+
49+
@BeforeEach
50+
void setUp() {
51+
Owner owner = new Owner();
52+
owner.setName("owner");
53+
entityManager.persist(owner);
54+
Book book = new Book();
55+
book.setOwner(owner);
56+
entityManager.persist(book);
57+
}
58+
59+
@Test
60+
void findAllByGenericAssociationProperty() {
61+
assertThat(repository.findAllByOwnerName("owner")).hasSize(1);
62+
}
63+
64+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2014-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.repository.sample;
17+
18+
import org.springframework.data.jpa.domain.sample.Book;
19+
import org.springframework.data.jpa.repository.JpaRepository;
20+
21+
import java.util.List;
22+
23+
/**
24+
* @author Yanming Zhou
25+
*/
26+
public interface BookRepository extends JpaRepository<Book, Long> {
27+
28+
List<Book> findAllByOwnerName(String ownerName);
29+
}

spring-data-jpa/src/test/resources/META-INF/persistence.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
1313
<class>org.springframework.data.jpa.domain.sample.AuditableEntity</class>
1414
<class>org.springframework.data.jpa.domain.sample.AuditableEmbeddable</class>
15+
<class>org.springframework.data.jpa.domain.sample.Book</class>
1516
<class>org.springframework.data.jpa.domain.sample.Category</class>
1617
<class>org.springframework.data.jpa.domain.sample.Child</class>
1718
<class>org.springframework.data.jpa.domain.sample.ConcreteType1</class>
@@ -33,6 +34,7 @@
3334
<class>org.springframework.data.jpa.domain.sample.MailSender</class>
3435
<class>org.springframework.data.jpa.domain.sample.MailUser</class>
3536
<class>org.springframework.data.jpa.domain.sample.Order</class>
37+
<class>org.springframework.data.jpa.domain.sample.Owner</class>
3638
<class>org.springframework.data.jpa.domain.sample.Parent</class>
3739
<class>org.springframework.data.jpa.domain.sample.PersistableWithIdClass</class>
3840
<class>org.springframework.data.jpa.domain.sample.PersistableWithSingleIdClass

spring-data-jpa/src/test/resources/META-INF/persistence2.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
99
<class>org.springframework.data.jpa.domain.sample.AuditableEntity</class>
1010
<class>org.springframework.data.jpa.domain.sample.AuditableEmbeddable</class>
11+
<class>org.springframework.data.jpa.domain.sample.Book</class>
1112
<class>org.springframework.data.jpa.domain.sample.Category</class>
1213
<class>org.springframework.data.jpa.domain.sample.CustomAbstractPersistable</class>
1314
<class>org.springframework.data.jpa.domain.sample.EntityWithAssignedId</class>
@@ -20,6 +21,7 @@
2021
<class>org.springframework.data.jpa.domain.sample.Role</class>
2122
<class>org.springframework.data.jpa.domain.sample.Site</class>
2223
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
24+
<class>org.springframework.data.jpa.domain.sample.Owner</class>
2325
<class>org.springframework.data.jpa.domain.sample.User</class>
2426
<class>org.springframework.data.jpa.domain.sample.Dummy</class>
2527
<exclude-unlisted-classes>true</exclude-unlisted-classes>

0 commit comments

Comments
 (0)