Skip to content

Commit c67073a

Browse files
authored
Fix MappedSuperclass for JPA entity attributes (#120)
* fix MappedSuperclass support * fix: set logging.level.org.hibernate=info
1 parent fc3c919 commit c67073a

File tree

8 files changed

+238
-14
lines changed

8 files changed

+238
-14
lines changed

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,7 @@
3636
import javax.persistence.Convert;
3737
import javax.persistence.EntityManager;
3838
import javax.persistence.Transient;
39-
import javax.persistence.metamodel.Attribute;
40-
import javax.persistence.metamodel.EmbeddableType;
41-
import javax.persistence.metamodel.EntityType;
42-
import javax.persistence.metamodel.ManagedType;
43-
import javax.persistence.metamodel.PluralAttribute;
44-
import javax.persistence.metamodel.SingularAttribute;
45-
import javax.persistence.metamodel.Type;
39+
import javax.persistence.metamodel.*;
4640

4741
import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
4842
import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
@@ -581,7 +575,7 @@ private List<GraphQLFieldDefinition> getEntityAttributesFields(EntityType<?> ent
581575
return entityType.getAttributes()
582576
.stream()
583577
.filter(this::isNotIgnored)
584-
.map(this::getObjectField)
578+
.map(it -> getObjectField(it, entityType))
585579
.collect(Collectors.toList());
586580
}
587581

@@ -608,9 +602,13 @@ private GraphQLFieldDefinition getJavaFieldDefinition(PropertyDescriptor propert
608602
.dataFetcher(dataFetcher)
609603
.build();
610604
}
611-
612-
@SuppressWarnings( { "rawtypes", "unchecked" } )
605+
613606
private GraphQLFieldDefinition getObjectField(Attribute attribute) {
607+
return getObjectField(attribute, null);
608+
}
609+
610+
@SuppressWarnings( { "rawtypes", "unchecked" } )
611+
private GraphQLFieldDefinition getObjectField(Attribute attribute, EntityType baseEntity) {
614612
GraphQLOutputType type = getAttributeOutputType(attribute);
615613

616614
List<GraphQLArgument> arguments = new ArrayList<>();
@@ -640,11 +638,11 @@ && isNotIgnoredOrder(attribute) ) {
640638
else if (attribute instanceof PluralAttribute
641639
&& (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_MANY
642640
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY)) {
643-
EntityType declaringType = (EntityType) ((PluralAttribute) attribute).getDeclaringType();
644-
ManagedType elementType = getForeignType(attribute);
641+
Assert.assertNotNull(baseEntity, "For attribute "+attribute.getName() + " cannot find declaring type!");
642+
EntityType elementType = (EntityType) ((PluralAttribute) attribute).getElementType();
645643

646644
arguments.add(getWhereArgument(elementType));
647-
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, declaringType, (PluralAttribute) attribute);
645+
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, baseEntity, (PluralAttribute) attribute);
648646
}
649647

650648
return GraphQLFieldDefinition.newFieldDefinition()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.introproventures.graphql.jpa.query.schema;
2+
3+
4+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
5+
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.boot.autoconfigure.SpringBootApplication;
10+
import org.springframework.boot.test.context.SpringBootTest;
11+
import org.springframework.context.annotation.Bean;
12+
import org.springframework.test.context.TestPropertySource;
13+
import org.springframework.test.context.junit4.SpringRunner;
14+
import org.springframework.util.Assert;
15+
16+
import javax.persistence.EntityManager;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
@RunWith(SpringRunner.class)
21+
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.NONE)
22+
@TestPropertySource({"classpath:hibernate.properties"})
23+
public class GraphQLExecutorSuperClassTests {
24+
25+
@SpringBootApplication
26+
static class Application {
27+
@Bean
28+
public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
29+
return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
30+
}
31+
32+
@Bean
33+
public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) {
34+
35+
return new GraphQLJpaSchemaBuilder(entityManager)
36+
.name("GraphQLBooks")
37+
.description("Books JPA test schema");
38+
}
39+
}
40+
41+
@Autowired
42+
private GraphQLExecutor executor;
43+
44+
@Test
45+
public void contextLoads() {
46+
Assert.isAssignable(GraphQLExecutor.class, executor.getClass());
47+
}
48+
49+
50+
@Test
51+
public void querySuperAuthors() {
52+
//given
53+
String query = "{ SuperAuthors { select { id name genre} }}";
54+
55+
String expected = "{SuperAuthors={select=[" +
56+
"{id=1, name=Leo Tolstoy, genre=NOVEL}, " +
57+
"{id=4, name=Anton Chekhov, genre=PLAY}" +
58+
"]}}";
59+
60+
//when
61+
Object result = executor.execute(query).getData();
62+
63+
// then
64+
assertThat(result.toString()).isEqualTo(expected);
65+
}
66+
67+
@Test
68+
public void querySuperBooks() {
69+
//given
70+
String query = "{ SuperBooks(where: {genre: {IN: PLAY}}) { select { id title, genre } }}";
71+
72+
String expected = "{SuperBooks={select=["
73+
+ "{id=5, title=The Cherry Orchard, genre=PLAY}, "
74+
+ "{id=6, title=The Seagull, genre=PLAY}, "
75+
+ "{id=7, title=Three Sisters, genre=PLAY}"
76+
+ "]}}";
77+
78+
//when
79+
Object result = executor.execute(query).getData();
80+
81+
// then
82+
assertThat(result.toString()).isEqualTo(expected);
83+
}
84+
}
85+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import javax.persistence.*;
7+
import java.util.Collection;
8+
import java.util.HashSet;
9+
import java.util.Set;
10+
11+
@MappedSuperclass
12+
@Getter
13+
@Setter
14+
public class BaseAuthor {
15+
@Id
16+
Long id;
17+
18+
@OneToMany(mappedBy="author", fetch= FetchType.LAZY)
19+
Collection<SuperBook> books;
20+
21+
@ElementCollection(fetch=FetchType.LAZY)
22+
@CollectionTable(name = "author_phone_numbers", joinColumns = @JoinColumn(name = "author_id"))
23+
@Column(name = "phone_number")
24+
private Set<String> phoneNumbers = new HashSet<>();
25+
26+
@Enumerated(EnumType.STRING)
27+
SuperGenre genre;
28+
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import javax.persistence.*;
7+
import java.util.Date;
8+
9+
@MappedSuperclass
10+
@Getter
11+
@Setter
12+
public class BaseBook {
13+
@Id
14+
Long id;
15+
16+
@ManyToOne(fetch= FetchType.LAZY)
17+
SuperAuthor author;
18+
19+
@Enumerated(EnumType.STRING)
20+
SuperGenre genre;
21+
22+
Date publicationDate;
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
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+
* http://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+
17+
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;
18+
19+
import lombok.EqualsAndHashCode;
20+
import lombok.Getter;
21+
import lombok.Setter;
22+
import lombok.ToString;
23+
24+
import javax.persistence.*;
25+
26+
@Entity
27+
@Table(name = "author")
28+
@Getter
29+
@Setter
30+
@ToString
31+
@EqualsAndHashCode(exclude={"books","phoneNumbers"}) // Fixes NPE in Hibernate when initializing loaded collections #1
32+
public class SuperAuthor extends BaseAuthor {
33+
34+
String name;
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
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+
* http://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+
17+
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;
18+
19+
import lombok.Data;
20+
21+
import javax.persistence.*;
22+
import java.util.Date;
23+
24+
@Data
25+
@Entity
26+
@Table(name = "book")
27+
public class SuperBook extends BaseBook {
28+
29+
String title;
30+
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
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+
* http://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+
17+
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;
18+
19+
public enum SuperGenre {
20+
NOVEL, PLAY
21+
}

graphql-jpa-query-schema/src/test/resources/hibernate.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ org.hibernate.stat=DEBUG
33
spring.jpa.properties.hibernate.show_sql=true
44
spring.jpa.properties.hibernate.format_sql=true
55

6-
logging.level.org.hibernate=debug
6+
logging.level.org.hibernate=info
77
#logging.level.org.hibernate.type.descriptor.sql=trace
88
#logging.level.org.hibernate.SQL=debug

0 commit comments

Comments
 (0)