Skip to content

Fix MappedSuperclass for JPA entity attributes #120

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

Merged
merged 9 commits into from
Apr 24, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@
import javax.persistence.Convert;
import javax.persistence.EntityManager;
import javax.persistence.Transient;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import javax.persistence.metamodel.*;

import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
Expand Down Expand Up @@ -581,7 +575,7 @@ private List<GraphQLFieldDefinition> getEntityAttributesFields(EntityType<?> ent
return entityType.getAttributes()
.stream()
.filter(this::isNotIgnored)
.map(this::getObjectField)
.map(it -> getObjectField(it, entityType))
.collect(Collectors.toList());
}

Expand All @@ -608,9 +602,13 @@ private GraphQLFieldDefinition getJavaFieldDefinition(PropertyDescriptor propert
.dataFetcher(dataFetcher)
.build();
}

@SuppressWarnings( { "rawtypes", "unchecked" } )

private GraphQLFieldDefinition getObjectField(Attribute attribute) {
return getObjectField(attribute, null);
}

@SuppressWarnings( { "rawtypes", "unchecked" } )
private GraphQLFieldDefinition getObjectField(Attribute attribute, EntityType baseEntity) {
GraphQLOutputType type = getAttributeOutputType(attribute);

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

arguments.add(getWhereArgument(elementType));
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, declaringType, (PluralAttribute) attribute);
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, baseEntity, (PluralAttribute) attribute);
}

return GraphQLFieldDefinition.newFieldDefinition()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.introproventures.graphql.jpa.query.schema;


import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.NONE)
@TestPropertySource({"classpath:hibernate.properties"})
public class GraphQLExecutorSuperClassTests {

@SpringBootApplication
static class Application {
@Bean
public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
}

@Bean
public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) {

return new GraphQLJpaSchemaBuilder(entityManager)
.name("GraphQLBooks")
.description("Books JPA test schema");
}
}

@Autowired
private GraphQLExecutor executor;

@Test
public void contextLoads() {
Assert.isAssignable(GraphQLExecutor.class, executor.getClass());
}


@Test
public void querySuperAuthors() {
//given
String query = "{ SuperAuthors { select { id name genre} }}";

String expected = "{SuperAuthors={select=[" +
"{id=1, name=Leo Tolstoy, genre=NOVEL}, " +
"{id=4, name=Anton Chekhov, genre=PLAY}" +
"]}}";

//when
Object result = executor.execute(query).getData();

// then
assertThat(result.toString()).isEqualTo(expected);
}

@Test
public void querySuperBooks() {
//given
String query = "{ SuperBooks(where: {genre: {IN: PLAY}}) { select { id title, genre } }}";

String expected = "{SuperBooks={select=["
+ "{id=5, title=The Cherry Orchard, genre=PLAY}, "
+ "{id=6, title=The Seagull, genre=PLAY}, "
+ "{id=7, title=Three Sisters, genre=PLAY}"
+ "]}}";

//when
Object result = executor.execute(query).getData();

// then
assertThat(result.toString()).isEqualTo(expected);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

@MappedSuperclass
@Getter
@Setter
public class BaseAuthor {
@Id
Long id;

@OneToMany(mappedBy="author", fetch= FetchType.LAZY)
Collection<SuperBook> books;

@ElementCollection(fetch=FetchType.LAZY)
@CollectionTable(name = "author_phone_numbers", joinColumns = @JoinColumn(name = "author_id"))
@Column(name = "phone_number")
private Set<String> phoneNumbers = new HashSet<>();

@Enumerated(EnumType.STRING)
SuperGenre genre;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.introproventures.graphql.jpa.query.schema.model.book_superclass;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.Date;

@MappedSuperclass
@Getter
@Setter
public class BaseBook {
@Id
Long id;

@ManyToOne(fetch= FetchType.LAZY)
SuperAuthor author;

@Enumerated(EnumType.STRING)
SuperGenre genre;

Date publicationDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.introproventures.graphql.jpa.query.schema.model.book_superclass;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;

@Entity
@Table(name = "author")
@Getter
@Setter
@ToString
@EqualsAndHashCode(exclude={"books","phoneNumbers"}) // Fixes NPE in Hibernate when initializing loaded collections #1
public class SuperAuthor extends BaseAuthor {

String name;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.introproventures.graphql.jpa.query.schema.model.book_superclass;

import lombok.Data;

import javax.persistence.*;
import java.util.Date;

@Data
@Entity
@Table(name = "book")
public class SuperBook extends BaseBook {

String title;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.introproventures.graphql.jpa.query.schema.model.book_superclass;

public enum SuperGenre {
NOVEL, PLAY
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ org.hibernate.stat=DEBUG
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

logging.level.org.hibernate=debug
logging.level.org.hibernate=info
#logging.level.org.hibernate.type.descriptor.sql=trace
#logging.level.org.hibernate.SQL=debug