From 1cbf29c21d845d75c291ec4bafd5e13b7b27b21c Mon Sep 17 00:00:00 2001 From: miklemv Date: Mon, 11 Mar 2019 06:55:43 +0300 Subject: [PATCH 1/8] support calcs fields and functions (#85) --- .../impl/CashGraphQLCalculatedFields.java | 66 ++++++++++++++++ .../schema/impl/GraphQLJpaSchemaBuilder.java | 71 ++++++++++++++++-- .../impl/QraphQLJpaBaseDataFetcher.java | 15 +--- .../jpa/query/schema/CalcEntityTests.java | 75 +++++++++++++++++++ .../query/schema/model/calc/CalcEntity.java | 46 ++++++++++++ .../src/test/resources/data.sql | 6 +- 6 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java create mode 100644 graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java create mode 100644 graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java new file mode 100644 index 000000000..262769fe1 --- /dev/null +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java @@ -0,0 +1,66 @@ +package com.introproventures.graphql.jpa.query.schema.impl; + + +import javax.persistence.Transient; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class CashGraphQLCalculatedFields { + protected static Map>> cashCalcFields = new ConcurrentHashMap<>(); + + public static void clearCashCalcFields() { + cashCalcFields.values().stream().forEach(v -> v.clear()); + cashCalcFields.clear(); + } + + public static boolean isCalcField(Class cls, String field) { + if (cashCalcFields.containsKey(cls)) { + if (cashCalcFields.get(cls).containsKey(field)) { + return cashCalcFields.get(cls).get(field).isPresent(); + } + } + + Optional cf = getTransient(cls, field); + addCashCalcFields(cls, field, cf); + + return cf.isPresent(); + } + + public static void addCashCalcFields(Class cls, String field, Optional an) { + if (!cashCalcFields.containsKey(cls)) { + Map> tpMap = new ConcurrentHashMap<>(); + cashCalcFields.put(cls, tpMap); + } + + cashCalcFields.get(cls).put(field, an); + } + + public static Optional getTransient(Class cls, String field) { + Optional calcField = Arrays.stream(cls.getDeclaredFields()) + .filter(f -> f.getName().equals(field) && f.isAnnotationPresent(Transient.class)) + .map(f -> f.getAnnotation(Transient.class)) + .findFirst(); + + if (!calcField.isPresent()) { + calcField = getGraphQLCalcMethod(cls, field, "get"); + } + + if (!calcField.isPresent()) { + calcField = getGraphQLCalcMethod(cls, field, "is"); + } + + return calcField; + } + + public static Optional getGraphQLCalcMethod(Class cls, String field, String prefix) { + String methodName = prefix + field.substring(0,1).toUpperCase() + field.substring(1); + + return Arrays.stream(cls.getDeclaredMethods()) + .filter(m -> m.getName().equals(methodName) && m.isAnnotationPresent(Transient.class)) + .map(m -> m.getAnnotation(Transient.class)) + .findFirst() + ; + } +} diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java index e08e3fbd6..4a35d16d5 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java @@ -24,16 +24,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.persistence.EntityManager; +import javax.persistence.Transient; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; @@ -469,6 +466,8 @@ private GraphQLObjectType getObjectType(EntityType entityType) { .map(this::getObjectField) .collect(Collectors.toList()) ) + .fields(getObjectCalcFields(entityType.getJavaType())) + .fields(getObjectCalcMethods(entityType.getJavaType())) .build(); entityCache.putIfAbsent(entityType, objectType); @@ -476,6 +475,68 @@ private GraphQLObjectType getObjectType(EntityType entityType) { return objectType; } + private List getObjectCalcFields(Class cls) { + return + Arrays.stream(cls.getDeclaredFields()) + .filter( + f -> + f instanceof Member && + f.isAnnotationPresent(Transient.class) && + isNotIgnored((Member) f) && + isNotIgnored(f.getType()) + ) + .map(f -> getObjectCalcField(f)) + .collect(Collectors.toList()); + } + + private List getObjectCalcMethods(Class cls) { + return + Arrays.stream(cls.getDeclaredMethods()) + .filter( + m -> + m instanceof Member && + m.isAnnotationPresent(Transient.class) && + isNotIgnored((Member) m) && + isNotIgnored(m.getReturnType()) + ) + .map(m -> getObjectCalcMethtod(m)) + .collect(Collectors.toList()); + } + + @SuppressWarnings( { "rawtypes", "unchecked" } ) + private GraphQLFieldDefinition getObjectCalcField(Field field) { + GraphQLType type = getGraphQLTypeFromJavaType(field.getType()); + DataFetcher dataFetcher = PropertyDataFetcher.fetching(field.getName()); + + return GraphQLFieldDefinition.newFieldDefinition() + .name(field.getName()) + .description(getSchemaDescription((AnnotatedElement) field)) + .type((GraphQLOutputType) type) + .dataFetcher(dataFetcher) + .build(); + } + + @SuppressWarnings( { "rawtypes", "unchecked" } ) + private GraphQLFieldDefinition getObjectCalcMethtod(Method method) { + String nm = method.getName(); + if (nm.startsWith("is")) { + nm = Introspector.decapitalize(nm.substring(2)); + } + if (nm.startsWith("get")) { + nm = Introspector.decapitalize(nm.substring(3)); + } + + GraphQLType type = getGraphQLTypeFromJavaType(method.getReturnType()); + DataFetcher dataFetcher = PropertyDataFetcher.fetching(nm); + + return GraphQLFieldDefinition.newFieldDefinition() + .name(nm) + .description(getSchemaDescription((AnnotatedElement) method)) + .type((GraphQLOutputType) type) + .dataFetcher(dataFetcher) + .build(); + } + @SuppressWarnings( { "rawtypes", "unchecked" } ) private GraphQLFieldDefinition getObjectField(Attribute attribute) { GraphQLOutputType type = getAttributeOutputType(attribute); diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java index c9627afe8..2fc8083e6 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java @@ -19,16 +19,7 @@ import static graphql.introspection.Introspection.TypeMetaFieldDef; import static graphql.introspection.Introspection.TypeNameMetaFieldDef; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -146,7 +137,7 @@ protected final List getFieldArguments(Field field, CriteriaQuery q Field selectedField = (Field) selection; // "__typename" is part of the graphql introspection spec and has to be ignored by jpa - if(!TYPENAME.equals(selectedField.getName())) { + if(!TYPENAME.equals(selectedField.getName()) && !CashGraphQLCalculatedFields.isCalcField(from.getJavaType(), selectedField.getName())) { Path fieldPath = from.get(selectedField.getName()); @@ -728,7 +719,7 @@ && isManagedType(entityType.getAttribute(it.getName())) Subgraph sg = entityGraph.addSubgraph(it.getName()); buildSubgraph(it, sg); } else { - if(!TYPENAME.equals(it.getName())) + if(!TYPENAME.equals(it.getName()) && !CashGraphQLCalculatedFields.isCalcField(entityType.getJavaType(), it.getName())) entityGraph.addAttributeNodes(it.getName()); } }); diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java new file mode 100644 index 000000000..70641cb8d --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java @@ -0,0 +1,75 @@ +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 CalcEntityTests { + @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("GraphQLCalcFields") + .description("CalcFields JPA test schema"); + } + + } + + @Autowired + private GraphQLExecutor executor; + + @Test + public void contextLoads() { + Assert.isAssignable(GraphQLExecutor.class, executor.getClass()); + } + + @Test + public void getAllRecords() { + //given + String query = "query GraphQLCalcFields { CalcEntities { select {id title fieldMem fieldFun logic customLogic } } }"; + + String expected = "{CalcEntities={select=[{id=1, title=title 1, fieldMem=member, fieldFun=title 1 function, logic=true, customLogic=false}, {id=2, title=title 2, fieldMem=member, fieldFun=title 2 function, logic=true, customLogic=false}]}}"; + + //when + Object result = executor.execute(query).getData(); + + //then + assertThat(result.toString()).isEqualTo(expected); + } + + @Test + public void testIgnoreFields() { + String query = "query GraphQLCalcFields { CalcEntities { select {id title fieldMem fieldFun logic customLogic hideField hideFieldFunction } } }"; + + String expected = "[ValidationError{validationErrorType=FieldUndefined, queryPath=[CalcEntities, select, hideField], message=Validation error of type FieldUndefined: Field 'hideField' in type 'CalcEntity' is undefined @ 'CalcEntities/select/hideField', locations=[SourceLocation{line=1, column=95}], description='Field 'hideField' in type 'CalcEntity' is undefined'}, ValidationError{validationErrorType=FieldUndefined, queryPath=[CalcEntities, select, hideFieldFunction], message=Validation error of type FieldUndefined: Field 'hideFieldFunction' in type 'CalcEntity' is undefined @ 'CalcEntities/select/hideFieldFunction', locations=[SourceLocation{line=1, column=105}], description='Field 'hideFieldFunction' in type 'CalcEntity' is undefined'}]"; + + //when + Object result = executor.execute(query).getErrors(); + + //then + assertThat(result.toString()).isEqualTo(expected); + } + +} diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java new file mode 100644 index 000000000..7411a33a8 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java @@ -0,0 +1,46 @@ +package com.introproventures.graphql.jpa.query.schema.model.calc; + +import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription; +import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore; +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Transient; + +@Data +@Entity +public class CalcEntity { + @Id + Long id; + + String title; + + String info; + + @Transient + boolean logic = true; + + @Transient + @GraphQLDescription("i desc member") + String fieldMem = "member"; + + @Transient + @GraphQLIgnore + String hideField = "hideField"; + + @Transient + @GraphQLDescription("i desc function") + public String getFieldFun() { + return title + " function"; + } + + @Transient + public boolean isCustomLogic() { + return false; + } + + public String getHideFieldFunction() { + return "getHideFieldFunction"; + } +} diff --git a/graphql-jpa-query-schema/src/test/resources/data.sql b/graphql-jpa-query-schema/src/test/resources/data.sql index 30ddb158b..9c580088e 100644 --- a/graphql-jpa-query-schema/src/test/resources/data.sql +++ b/graphql-jpa-query-schema/src/test/resources/data.sql @@ -133,4 +133,8 @@ insert into Boat (id, country, identification) values (1, 'EN', '12345'), (2, 'EN', '23456'), (1, 'FR', '34567'); - \ No newline at end of file + +-- Calculate entity +insert into calc_entity (id, title, info) values + (1, 'title 1', 'inf 1'), + (2, 'title 2', 'inf 2'); From 493f65daa0e95d50a2ee8787af4444bcb365c2ed Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 21:10:18 -0700 Subject: [PATCH 2/8] Refactor SchemaBuilder using Introspection (#86) * fix: refactor introspection using BeanInfo * fix: polish GraphQLSchemaBuilder implementation --- .../impl/CashGraphQLCalculatedFields.java | 66 --------- .../schema/impl/GraphQLJpaSchemaBuilder.java | 135 +++++++----------- .../query/schema/impl/IntrospectionUtils.java | 95 ++++++++++++ .../impl/QraphQLJpaBaseDataFetcher.java | 15 +- ...yTests.java => CalculatedEntityTests.java} | 34 +++-- .../schema/impl/IntrospectionUtilsTest.java | 55 +++++++ .../CalculatedEntity.java} | 16 ++- .../src/test/resources/data.sql | 2 +- 8 files changed, 244 insertions(+), 174 deletions(-) delete mode 100644 graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java create mode 100644 graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtils.java rename graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/{CalcEntityTests.java => CalculatedEntityTests.java} (57%) create mode 100644 graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtilsTest.java rename graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/{calc/CalcEntity.java => calculated/CalculatedEntity.java} (94%) diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java deleted file mode 100644 index 262769fe1..000000000 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/CashGraphQLCalculatedFields.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.introproventures.graphql.jpa.query.schema.impl; - - -import javax.persistence.Transient; -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -public class CashGraphQLCalculatedFields { - protected static Map>> cashCalcFields = new ConcurrentHashMap<>(); - - public static void clearCashCalcFields() { - cashCalcFields.values().stream().forEach(v -> v.clear()); - cashCalcFields.clear(); - } - - public static boolean isCalcField(Class cls, String field) { - if (cashCalcFields.containsKey(cls)) { - if (cashCalcFields.get(cls).containsKey(field)) { - return cashCalcFields.get(cls).get(field).isPresent(); - } - } - - Optional cf = getTransient(cls, field); - addCashCalcFields(cls, field, cf); - - return cf.isPresent(); - } - - public static void addCashCalcFields(Class cls, String field, Optional an) { - if (!cashCalcFields.containsKey(cls)) { - Map> tpMap = new ConcurrentHashMap<>(); - cashCalcFields.put(cls, tpMap); - } - - cashCalcFields.get(cls).put(field, an); - } - - public static Optional getTransient(Class cls, String field) { - Optional calcField = Arrays.stream(cls.getDeclaredFields()) - .filter(f -> f.getName().equals(field) && f.isAnnotationPresent(Transient.class)) - .map(f -> f.getAnnotation(Transient.class)) - .findFirst(); - - if (!calcField.isPresent()) { - calcField = getGraphQLCalcMethod(cls, field, "get"); - } - - if (!calcField.isPresent()) { - calcField = getGraphQLCalcMethod(cls, field, "is"); - } - - return calcField; - } - - public static Optional getGraphQLCalcMethod(Class cls, String field, String prefix) { - String methodName = prefix + field.substring(0,1).toUpperCase() + field.substring(1); - - return Arrays.stream(cls.getDeclaredMethods()) - .filter(m -> m.getName().equals(methodName) && m.isAnnotationPresent(Transient.class)) - .map(m -> m.getAnnotation(Transient.class)) - .findFirst() - ; - } -} diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java index 4a35d16d5..7a00249b9 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java @@ -24,7 +24,11 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -47,6 +51,7 @@ import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder; import com.introproventures.graphql.jpa.query.schema.JavaScalars; import com.introproventures.graphql.jpa.query.schema.NamingStrategy; +import com.introproventures.graphql.jpa.query.schema.impl.IntrospectionUtils.CachedIntrospectionResult.CachedPropertyDescriptor; import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria; import graphql.Assert; @@ -92,7 +97,7 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder { public static final String ORDER_BY_PARAM_NAME = "orderBy"; - private Map, GraphQLType> classCache = new HashMap<>(); + private Map, GraphQLOutputType> classCache = new HashMap<>(); private Map, GraphQLObjectType> entityCache = new HashMap<>(); private Map, GraphQLObjectType> embeddableOutputCache = new HashMap<>(); private Map, GraphQLInputObjectType> embeddableInputCache = new HashMap<>(); @@ -205,7 +210,7 @@ private GraphQLArgument getWhereArgument(ManagedType managedType) { if (managedType instanceof EmbeddableType){ typeName = managedType.getJavaType().getSimpleName()+"EmbeddableType"; } else if (managedType instanceof EntityType) { - typeName = ((EntityType)managedType).getName(); + typeName = ((EntityType)managedType).getName(); } String type = namingStrategy.pluralize(typeName)+"CriteriaExpression"; @@ -251,14 +256,14 @@ private GraphQLArgument getWhereArgument(ManagedType managedType) { } private GraphQLInputObjectField getWhereInputField(Attribute attribute) { - GraphQLType type = getWhereAttributeType(attribute); + GraphQLInputType type = getWhereAttributeType(attribute); String description = getSchemaDescription(attribute.getJavaMember()); if (type instanceof GraphQLInputType) { return GraphQLInputObjectField.newInputObjectField() .name(attribute.getName()) .description(description) - .type((GraphQLInputType) type) + .type(type) .build(); } @@ -409,7 +414,7 @@ private GraphQLArgument getArgument(Attribute attribute) { return GraphQLArgument.newArgument() .name(attribute.getName()) - .type((GraphQLInputType) type) + .type(type) .description(description) .build(); } @@ -454,89 +459,51 @@ private GraphQLType getEmbeddableType(EmbeddableType embeddableType, boolean private GraphQLObjectType getObjectType(EntityType entityType) { - if (entityCache.containsKey(entityType)) - return entityCache.get(entityType); - - - GraphQLObjectType objectType = GraphQLObjectType.newObject() - .name(entityType.getName()) - .description(getSchemaDescription( entityType.getJavaType())) - .fields(entityType.getAttributes().stream() - .filter(this::isNotIgnored) - .map(this::getObjectField) - .collect(Collectors.toList()) - ) - .fields(getObjectCalcFields(entityType.getJavaType())) - .fields(getObjectCalcMethods(entityType.getJavaType())) - .build(); - - entityCache.putIfAbsent(entityType, objectType); - - return objectType; - } - - private List getObjectCalcFields(Class cls) { - return - Arrays.stream(cls.getDeclaredFields()) - .filter( - f -> - f instanceof Member && - f.isAnnotationPresent(Transient.class) && - isNotIgnored((Member) f) && - isNotIgnored(f.getType()) - ) - .map(f -> getObjectCalcField(f)) - .collect(Collectors.toList()); - } - - private List getObjectCalcMethods(Class cls) { - return - Arrays.stream(cls.getDeclaredMethods()) - .filter( - m -> - m instanceof Member && - m.isAnnotationPresent(Transient.class) && - isNotIgnored((Member) m) && - isNotIgnored(m.getReturnType()) - ) - .map(m -> getObjectCalcMethtod(m)) - .collect(Collectors.toList()); + return entityCache.computeIfAbsent(entityType, this::computeObjectType); } - - @SuppressWarnings( { "rawtypes", "unchecked" } ) - private GraphQLFieldDefinition getObjectCalcField(Field field) { - GraphQLType type = getGraphQLTypeFromJavaType(field.getType()); - DataFetcher dataFetcher = PropertyDataFetcher.fetching(field.getName()); - - return GraphQLFieldDefinition.newFieldDefinition() - .name(field.getName()) - .description(getSchemaDescription((AnnotatedElement) field)) - .type((GraphQLOutputType) type) - .dataFetcher(dataFetcher) - .build(); + + + private GraphQLObjectType computeObjectType(EntityType entityType) { + return GraphQLObjectType.newObject() + .name(entityType.getName()) + .description(getSchemaDescription(entityType.getJavaType())) + .fields(getEntityAttributesFields(entityType)) + .fields(getTransientFields(entityType.getJavaType())) + .build(); } - @SuppressWarnings( { "rawtypes", "unchecked" } ) - private GraphQLFieldDefinition getObjectCalcMethtod(Method method) { - String nm = method.getName(); - if (nm.startsWith("is")) { - nm = Introspector.decapitalize(nm.substring(2)); - } - if (nm.startsWith("get")) { - nm = Introspector.decapitalize(nm.substring(3)); - } + private List getEntityAttributesFields(EntityType entityType) { + return entityType.getAttributes() + .stream() + .filter(this::isNotIgnored) + .map(this::getObjectField) + .collect(Collectors.toList()); + } - GraphQLType type = getGraphQLTypeFromJavaType(method.getReturnType()); - DataFetcher dataFetcher = PropertyDataFetcher.fetching(nm); + + private List getTransientFields(Class clazz) { + return IntrospectionUtils.introspect(clazz) + .getPropertyDescriptors().stream() + .filter(it -> it.isAnnotationPresent(Transient.class)) + .map(CachedPropertyDescriptor::getDelegate) + .filter(it -> isNotIgnored(it.getPropertyType())) + .map(this::getJavaFieldDefinition) + .collect(Collectors.toList()); + } + + @SuppressWarnings( { "rawtypes" } ) + private GraphQLFieldDefinition getJavaFieldDefinition(PropertyDescriptor propertyDescriptor) { + GraphQLOutputType type = getGraphQLTypeFromJavaType(propertyDescriptor.getPropertyType()); + DataFetcher dataFetcher = PropertyDataFetcher.fetching(propertyDescriptor.getName()); return GraphQLFieldDefinition.newFieldDefinition() - .name(nm) - .description(getSchemaDescription((AnnotatedElement) method)) - .type((GraphQLOutputType) type) + .name(propertyDescriptor.getName()) + .description(getSchemaDescription(propertyDescriptor.getPropertyType())) + .type(type) .dataFetcher(dataFetcher) .build(); } - + @SuppressWarnings( { "rawtypes", "unchecked" } ) private GraphQLFieldDefinition getObjectField(Attribute attribute) { GraphQLOutputType type = getAttributeOutputType(attribute); @@ -583,7 +550,7 @@ else if (attribute instanceof PluralAttribute .build(); } - @SuppressWarnings( { "rawtypes", "unchecked" } ) + @SuppressWarnings( { "rawtypes" } ) private GraphQLInputObjectField getInputObjectField(Attribute attribute) { GraphQLInputType type = getAttributeInputType(attribute); @@ -598,7 +565,6 @@ private Stream> findBasicAttributes(Collection> at return attributes.stream().filter(it -> it.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC); } - @SuppressWarnings( "rawtypes" ) private GraphQLInputType getAttributeInputType(Attribute attribute) { try{ return (GraphQLInputType) getAttributeType(attribute, true); @@ -607,7 +573,6 @@ private GraphQLInputType getAttributeInputType(Attribute attribute) { } } - @SuppressWarnings( "rawtypes" ) private GraphQLOutputType getAttributeOutputType(Attribute attribute) { try { return (GraphQLOutputType) getAttributeType(attribute, false); @@ -786,7 +751,7 @@ private boolean isNotIgnored(AnnotatedElement annotatedElement) { } @SuppressWarnings( "unchecked" ) - private GraphQLType getGraphQLTypeFromJavaType(Class clazz) { + private GraphQLOutputType getGraphQLTypeFromJavaType(Class clazz) { if (clazz.isEnum()) { if (classCache.containsKey(clazz)) @@ -797,7 +762,7 @@ private GraphQLType getGraphQLTypeFromJavaType(Class clazz) { for (Enum enumValue : ((Class>)clazz).getEnumConstants()) enumBuilder.value(enumValue.name(), ordinal++); - GraphQLType enumType = enumBuilder.build(); + GraphQLEnumType enumType = enumBuilder.build(); setNoOpCoercing(enumType); classCache.putIfAbsent(clazz, enumType); diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtils.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtils.java new file mode 100644 index 000000000..ebb2341cd --- /dev/null +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtils.java @@ -0,0 +1,95 @@ +package com.introproventures.graphql.jpa.query.schema.impl; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.persistence.Transient; + +public class IntrospectionUtils { + private static final Map, CachedIntrospectionResult> map = new LinkedHashMap<>(); + + public static CachedIntrospectionResult introspect(Class entity) { + return map.computeIfAbsent(entity, CachedIntrospectionResult::new); + } + + public static boolean isTransient(Class entity, String propertyName) { + return introspect(entity).getPropertyDescriptor(propertyName) + .map(it -> it.isAnnotationPresent(Transient.class)) + .orElseThrow(() -> new RuntimeException(new NoSuchFieldException(propertyName))); + } + + public static class CachedIntrospectionResult { + + private final Map map; + private final Class entity; + private final BeanInfo beanInfo; + + public CachedIntrospectionResult(Class entity) { + try { + this.beanInfo = Introspector.getBeanInfo(entity); + } catch (IntrospectionException cause) { + throw new RuntimeException(cause); + } + + this.entity = entity; + this.map = Stream.of(beanInfo.getPropertyDescriptors()) + .map(CachedPropertyDescriptor::new) + .collect(Collectors.toMap(CachedPropertyDescriptor::getName, it -> it)); + } + + public Collection getPropertyDescriptors() { + return map.values(); + } + + public Optional getPropertyDescriptor(String fieldName) { + return Optional.ofNullable(map.getOrDefault(fieldName, null)); + } + + public Class getEntity() { + return entity; + } + + public BeanInfo getBeanInfo() { + return beanInfo; + } + + public class CachedPropertyDescriptor { + private final PropertyDescriptor delegate; + + public CachedPropertyDescriptor(PropertyDescriptor delegate) { + this.delegate = delegate; + } + + public PropertyDescriptor getDelegate() { + return delegate; + } + + public String getName() { + return delegate.getName(); + } + + public boolean isAnnotationPresent(Class annotation) { + boolean answer; + try { + answer = entity.getDeclaredField(delegate.getName()) + .isAnnotationPresent(annotation); + + } catch (NoSuchFieldException e) { + answer = delegate.getReadMethod() + .isAnnotationPresent(annotation); + } + return answer; + } + + } + } +} diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java index 2fc8083e6..a901ff915 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java @@ -19,7 +19,16 @@ import static graphql.introspection.Introspection.TypeMetaFieldDef; import static graphql.introspection.Introspection.TypeNameMetaFieldDef; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -137,7 +146,7 @@ protected final List getFieldArguments(Field field, CriteriaQuery q Field selectedField = (Field) selection; // "__typename" is part of the graphql introspection spec and has to be ignored by jpa - if(!TYPENAME.equals(selectedField.getName()) && !CashGraphQLCalculatedFields.isCalcField(from.getJavaType(), selectedField.getName())) { + if(!TYPENAME.equals(selectedField.getName()) && !IntrospectionUtils.isTransient(from.getJavaType(), selectedField.getName())) { Path fieldPath = from.get(selectedField.getName()); @@ -719,7 +728,7 @@ && isManagedType(entityType.getAttribute(it.getName())) Subgraph sg = entityGraph.addSubgraph(it.getName()); buildSubgraph(it, sg); } else { - if(!TYPENAME.equals(it.getName()) && !CashGraphQLCalculatedFields.isCalcField(entityType.getJavaType(), it.getName())) + if(!TYPENAME.equals(it.getName()) && !IntrospectionUtils.isTransient(entityType.getJavaType(), it.getName())) entityGraph.addAttributeNodes(it.getName()); } }); diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalculatedEntityTests.java similarity index 57% rename from graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java rename to graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalculatedEntityTests.java index 70641cb8d..c63167e7b 100644 --- a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalcEntityTests.java +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/CalculatedEntityTests.java @@ -1,7 +1,12 @@ 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 static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; + +import javax.persistence.EntityManager; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -12,14 +17,17 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.Assert; -import javax.persistence.EntityManager; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; +import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; -import static org.assertj.core.api.Assertions.assertThat; +import graphql.ErrorType; +import graphql.GraphQLError; +import graphql.validation.ValidationError; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.NONE) @TestPropertySource({"classpath:hibernate.properties"}) -public class CalcEntityTests { +public class CalculatedEntityTests { @SpringBootApplication static class Application { @Bean @@ -48,9 +56,9 @@ public void contextLoads() { @Test public void getAllRecords() { //given - String query = "query GraphQLCalcFields { CalcEntities { select {id title fieldMem fieldFun logic customLogic } } }"; + String query = "query GraphQLCalcFields { CalculatedEntities { select {id title fieldMem fieldFun logic customLogic } } }"; - String expected = "{CalcEntities={select=[{id=1, title=title 1, fieldMem=member, fieldFun=title 1 function, logic=true, customLogic=false}, {id=2, title=title 2, fieldMem=member, fieldFun=title 2 function, logic=true, customLogic=false}]}}"; + String expected = "{CalculatedEntities={select=[{id=1, title=title 1, fieldMem=member, fieldFun=title 1 function, logic=true, customLogic=false}, {id=2, title=title 2, fieldMem=member, fieldFun=title 2 function, logic=true, customLogic=false}]}}"; //when Object result = executor.execute(query).getData(); @@ -61,15 +69,17 @@ public void getAllRecords() { @Test public void testIgnoreFields() { - String query = "query GraphQLCalcFields { CalcEntities { select {id title fieldMem fieldFun logic customLogic hideField hideFieldFunction } } }"; - - String expected = "[ValidationError{validationErrorType=FieldUndefined, queryPath=[CalcEntities, select, hideField], message=Validation error of type FieldUndefined: Field 'hideField' in type 'CalcEntity' is undefined @ 'CalcEntities/select/hideField', locations=[SourceLocation{line=1, column=95}], description='Field 'hideField' in type 'CalcEntity' is undefined'}, ValidationError{validationErrorType=FieldUndefined, queryPath=[CalcEntities, select, hideFieldFunction], message=Validation error of type FieldUndefined: Field 'hideFieldFunction' in type 'CalcEntity' is undefined @ 'CalcEntities/select/hideFieldFunction', locations=[SourceLocation{line=1, column=105}], description='Field 'hideFieldFunction' in type 'CalcEntity' is undefined'}]"; + String query = "query GraphQLCalcFields { CalculatedEntities { select {id title fieldMem fieldFun logic customLogic hideField hideFieldFunction } } }"; //when - Object result = executor.execute(query).getErrors(); + List result = executor.execute(query).getErrors(); //then - assertThat(result.toString()).isEqualTo(expected); + assertThat(result).hasSize(1); + assertThat(result.get(0)).isExactlyInstanceOf(ValidationError.class) + .extracting(ValidationError.class::cast) + .extracting("errorType", "queryPath") + .contains(ErrorType.ValidationError, Arrays.asList("CalculatedEntities", "select", "hideFieldFunction")); } } diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtilsTest.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtilsTest.java new file mode 100644 index 000000000..0510e9db1 --- /dev/null +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/impl/IntrospectionUtilsTest.java @@ -0,0 +1,55 @@ +package com.introproventures.graphql.jpa.query.schema.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +import com.introproventures.graphql.jpa.query.schema.model.calculated.CalculatedEntity; + +public class IntrospectionUtilsTest { + + // given + Class entity = CalculatedEntity.class; + + + @Test(expected=RuntimeException.class) + public void testIsTransientNonExisting() throws Exception { + // then + assertThat(IntrospectionUtils.isTransient(entity, "notFound")).isFalse(); + } + + @Test + public void testIsTransientClass() throws Exception { + // then + assertThat(IntrospectionUtils.isTransient(entity, "class")).isFalse(); + } + + @Test + public void testIsTransientFunction() throws Exception { + // then + assertThat(IntrospectionUtils.isTransient(entity, "fieldFun")).isTrue(); + assertThat(IntrospectionUtils.isTransient(entity, "hideFieldFunction")).isFalse(); + } + + @Test + public void testIsTransientFields() throws Exception { + // then + assertThat(IntrospectionUtils.isTransient(entity, "fieldFun")).isTrue(); + assertThat(IntrospectionUtils.isTransient(entity, "fieldMem")).isTrue(); + assertThat(IntrospectionUtils.isTransient(entity, "hideField")).isTrue(); + assertThat(IntrospectionUtils.isTransient(entity, "logic")).isTrue(); + } + + @Test + public void testNotTransientFields() throws Exception { + // given + Class entity = CalculatedEntity.class; + + // then + assertThat(IntrospectionUtils.isTransient(entity, "id")).isFalse(); + assertThat(IntrospectionUtils.isTransient(entity, "info")).isFalse(); + assertThat(IntrospectionUtils.isTransient(entity, "title")).isFalse(); + } + + +} diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java similarity index 94% rename from graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java rename to graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java index 7411a33a8..e312c7bfa 100644 --- a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calc/CalcEntity.java +++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java @@ -1,16 +1,17 @@ -package com.introproventures.graphql.jpa.query.schema.model.calc; - -import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription; -import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore; -import lombok.Data; +package com.introproventures.graphql.jpa.query.schema.model.calculated; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Transient; +import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription; +import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore; + +import lombok.Data; + @Data @Entity -public class CalcEntity { +public class CalculatedEntity { @Id Long id; @@ -20,7 +21,7 @@ public class CalcEntity { @Transient boolean logic = true; - + @Transient @GraphQLDescription("i desc member") String fieldMem = "member"; @@ -29,6 +30,7 @@ public class CalcEntity { @GraphQLIgnore String hideField = "hideField"; + @Transient @GraphQLDescription("i desc function") public String getFieldFun() { diff --git a/graphql-jpa-query-schema/src/test/resources/data.sql b/graphql-jpa-query-schema/src/test/resources/data.sql index 9c580088e..d622bc616 100644 --- a/graphql-jpa-query-schema/src/test/resources/data.sql +++ b/graphql-jpa-query-schema/src/test/resources/data.sql @@ -135,6 +135,6 @@ insert into Boat (id, country, identification) values (1, 'FR', '34567'); -- Calculate entity -insert into calc_entity (id, title, info) values +insert into calculated_entity (id, title, info) values (1, 'title 1', 'inf 1'), (2, 'title 2', 'inf 2'); From ee0aa6c9ad5fead0f5a15e2133460fdebb9a0724 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 21:25:57 -0700 Subject: [PATCH 3/8] fix: upgrade to Spring Boot 2.1.3.RELEASE (#87) --- graphql-jpa-query-build/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphql-jpa-query-build/pom.xml b/graphql-jpa-query-build/pom.xml index 1396d276f..3e5d72b92 100644 --- a/graphql-jpa-query-build/pom.xml +++ b/graphql-jpa-query-build/pom.xml @@ -15,7 +15,7 @@ org.springframework.boot spring-boot-dependencies - 2.1.0.RELEASE + 2.1.3.RELEASE pom import From f838056009ca884d45e451b96a7a28dd8f9ea5a1 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 22:38:04 -0700 Subject: [PATCH 4/8] fix: Configuration properties are ignored when merging bug (#88) * fix: extract GraphQLShemaRegistration interface * fix: configuration properties are ignored when merging * fix: add graphQLSchema query type configuration test * feat: provide name configs for GraphQLSchemaFactoryBean query types --- graphql-jpa-query-autoconfigure/pom.xml | 10 +++ .../GraphQLJpaQueryProperties.java | 11 ++- .../GraphQLSchemaAutoConfiguration.java | 17 ++++- .../GraphQLSchemaFactoryBean.java | 74 +++++++++++++++++-- .../GraphQLShemaRegistration.java | 14 +--- .../GraphQLShemaRegistrationImpl.java | 20 +++++ .../boot/autoconfigure/default.properties | 4 + .../GraphQLSchemaAutoConfigurationTest.java | 16 ++-- .../src/test/resources/application.yml | 14 ++++ .../autoconfigure/EnableGraphQLJpaQuery.java | 37 ---------- .../GraphQLJpaQueryAutoConfiguration.java | 39 +++------- .../EnableGraphQLJpaQueryTest.java | 69 ----------------- .../GraphQLJpaQueryAutoConfigurationTest.java | 27 ++++--- .../schema/impl/GraphQLJpaSchemaBuilder.java | 2 +- 14 files changed, 179 insertions(+), 175 deletions(-) rename {graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot => graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query}/autoconfigure/GraphQLJpaQueryProperties.java (83%) create mode 100644 graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistrationImpl.java create mode 100644 graphql-jpa-query-autoconfigure/src/main/resources/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties create mode 100644 graphql-jpa-query-autoconfigure/src/test/resources/application.yml delete mode 100644 graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQuery.java delete mode 100644 graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQueryTest.java diff --git a/graphql-jpa-query-autoconfigure/pom.xml b/graphql-jpa-query-autoconfigure/pom.xml index 65878745d..c749bf258 100644 --- a/graphql-jpa-query-autoconfigure/pom.xml +++ b/graphql-jpa-query-autoconfigure/pom.xml @@ -19,7 +19,17 @@ org.springframework.boot spring-boot-autoconfigure + + + javax.validation + validation-api + + + org.hibernate.validator + hibernate-validator + test + \ No newline at end of file diff --git a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryProperties.java b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLJpaQueryProperties.java similarity index 83% rename from graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryProperties.java rename to graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLJpaQueryProperties.java index 4c3ee3a03..5383630ee 100644 --- a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryProperties.java +++ b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLJpaQueryProperties.java @@ -13,13 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.introproventures.graphql.jpa.query.boot.autoconfigure; +package com.introproventures.graphql.jpa.query.autoconfigure; + +import javax.validation.constraints.NotEmpty; -import org.hibernate.validator.constraints.NotEmpty; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; import org.springframework.validation.annotation.Validated; @ConfigurationProperties(prefix="spring.graphql.jpa.query") +@PropertySources(value= { + @PropertySource("classpath:/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties"), + @PropertySource(value = "classpath:graphql-jpa-autoconfigure.properties", ignoreResourceNotFound = true) +}) @Validated public class GraphQLJpaQueryProperties { diff --git a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfiguration.java b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfiguration.java index 2842940b3..21c524178 100644 --- a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfiguration.java +++ b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfiguration.java @@ -3,20 +3,26 @@ import java.util.ArrayList; import java.util.List; -import graphql.GraphQL; -import graphql.schema.GraphQLSchema; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.CollectionUtils; +import graphql.GraphQL; +import graphql.schema.GraphQLSchema; + @Configuration @ConditionalOnClass(GraphQL.class) +@EnableConfigurationProperties(GraphQLJpaQueryProperties.class) public class GraphQLSchemaAutoConfiguration { private final List graphQLSchemaConfigurers = new ArrayList<>(); + + @Autowired + private GraphQLJpaQueryProperties properties; @Autowired(required = true) public void setGraphQLSchemaConfigurers(List configurers) { @@ -28,13 +34,16 @@ public void setGraphQLSchemaConfigurers(List configurer @Bean @ConditionalOnMissingBean(GraphQLSchema.class) public GraphQLSchemaFactoryBean graphQLSchemaFactoryBean() { - GraphQLShemaRegistration graphQLShemaRegistration = new GraphQLShemaRegistration(); + GraphQLShemaRegistrationImpl graphQLShemaRegistration = new GraphQLShemaRegistrationImpl(); for (GraphQLSchemaConfigurer configurer : graphQLSchemaConfigurers) { configurer.configure(graphQLShemaRegistration); } - return new GraphQLSchemaFactoryBean(graphQLShemaRegistration.getManagedGraphQLSchemas()); + return new GraphQLSchemaFactoryBean(graphQLShemaRegistration.getManagedGraphQLSchemas()) + .setQueryName(properties.getName()) + .setQueryDescription(properties.getDescription()); + }; diff --git a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaFactoryBean.java b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaFactoryBean.java index 02499123b..92837b666 100644 --- a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaFactoryBean.java +++ b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaFactoryBean.java @@ -5,15 +5,34 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.beans.factory.config.AbstractFactoryBean; + import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; -import org.springframework.beans.factory.config.AbstractFactoryBean; public class GraphQLSchemaFactoryBean extends AbstractFactoryBean{ - private final GraphQLSchema[] managedGraphQLSchemas; + private static final String QUERY_NAME = "Query"; + private static final String QUERY_DESCRIPTION = ""; + private static final String SUBSCRIPTION_NAME = "Subscription"; + private static final String SUBSCRIPTION_DESCRIPTION = ""; + private static final String MUTATION_NAME = "Mutation"; + private static final String MUTATION_DESCRIPTION = ""; + + + private final GraphQLSchema[] managedGraphQLSchemas; + + private String queryName = QUERY_NAME; + private String queryDescription = QUERY_DESCRIPTION; + + private String subscriptionName = SUBSCRIPTION_NAME; + private String subscriptionDescription = SUBSCRIPTION_DESCRIPTION; + private String mutationName = MUTATION_NAME; + private String mutationDescription = MUTATION_DESCRIPTION; + + public GraphQLSchemaFactoryBean(GraphQLSchema[] managedGraphQLSchemas) { this.managedGraphQLSchemas = managedGraphQLSchemas; } @@ -46,13 +65,22 @@ protected GraphQLSchema createInstance() throws Exception { .collect(Collectors.toList()); if(!mutations.isEmpty()) - schemaBuilder.mutation(GraphQLObjectType.newObject().name("Mutation").fields(mutations)); + schemaBuilder.mutation(GraphQLObjectType.newObject() + .name(this.mutationName) + .description(this.mutationDescription) + .fields(mutations)); if(!queries.isEmpty()) - schemaBuilder.query(GraphQLObjectType.newObject().name("Query").fields(queries)); + schemaBuilder.query(GraphQLObjectType.newObject() + .name(this.queryName) + .description(this.queryDescription) + .fields(queries)); if(!subscriptions.isEmpty()) - schemaBuilder.subscription(GraphQLObjectType.newObject().name("Subscription").fields(subscriptions)); + schemaBuilder.subscription(GraphQLObjectType.newObject() + .name(this.subscriptionName) + .description(this.subscriptionDescription) + .fields(subscriptions)); return schemaBuilder.build(); } @@ -62,4 +90,40 @@ public Class getObjectType() { return GraphQLSchema.class; } + public GraphQLSchemaFactoryBean setQueryName(String name) { + this.queryName = name; + + return this; + } + + public GraphQLSchemaFactoryBean setQueryDescription(String description) { + this.queryDescription = description; + + return this; + } + + public GraphQLSchemaFactoryBean setSubscriptionName(String subscriptionName) { + this.subscriptionName = subscriptionName; + + return this; + } + + public GraphQLSchemaFactoryBean setSubscriptionDescription(String subscriptionDescription) { + this.subscriptionDescription = subscriptionDescription; + + return this; + } + + public GraphQLSchemaFactoryBean setMutationName(String mutationName) { + this.mutationName = mutationName; + + return this; + } + + public GraphQLSchemaFactoryBean setMutationDescription(String mutationDescription) { + this.mutationDescription = mutationDescription; + + return this; + } + } diff --git a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistration.java b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistration.java index b91e17632..296734e59 100644 --- a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistration.java +++ b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistration.java @@ -1,20 +1,10 @@ package com.introproventures.graphql.jpa.query.autoconfigure; -import java.util.LinkedHashSet; -import java.util.Set; - import graphql.schema.GraphQLSchema; -public class GraphQLShemaRegistration { - - Set managedGraphQLSchemas = new LinkedHashSet(); +public interface GraphQLShemaRegistration { - public void register(GraphQLSchema graphQLSchema) { - managedGraphQLSchemas.add(graphQLSchema); - } + public void register(GraphQLSchema graphQLSchema); - public GraphQLSchema[] getManagedGraphQLSchemas() { - return managedGraphQLSchemas.toArray(new GraphQLSchema[] {}); - } } diff --git a/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistrationImpl.java b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistrationImpl.java new file mode 100644 index 000000000..a0a17f3b7 --- /dev/null +++ b/graphql-jpa-query-autoconfigure/src/main/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLShemaRegistrationImpl.java @@ -0,0 +1,20 @@ +package com.introproventures.graphql.jpa.query.autoconfigure; + +import java.util.LinkedHashSet; +import java.util.Set; + +import graphql.schema.GraphQLSchema; + +public class GraphQLShemaRegistrationImpl implements GraphQLShemaRegistration { + + Set managedGraphQLSchemas = new LinkedHashSet(); + + public void register(GraphQLSchema graphQLSchema) { + managedGraphQLSchemas.add(graphQLSchema); + } + + public GraphQLSchema[] getManagedGraphQLSchemas() { + return managedGraphQLSchemas.toArray(new GraphQLSchema[] {}); + } + +} diff --git a/graphql-jpa-query-autoconfigure/src/main/resources/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties b/graphql-jpa-query-autoconfigure/src/main/resources/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties new file mode 100644 index 000000000..8a9deba1d --- /dev/null +++ b/graphql-jpa-query-autoconfigure/src/main/resources/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties @@ -0,0 +1,4 @@ +spring.graphql.jpa.query.name=Query +spring.graphql.jpa.query.description= +spring.graphql.jpa.query.enabled=true +spring.graphql.jpa.query.path=/graphql \ No newline at end of file diff --git a/graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java b/graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java index 09129b729..e8cd94c6c 100644 --- a/graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java +++ b/graphql-jpa-query-autoconfigure/src/test/java/com/introproventures/graphql/jpa/query/autoconfigure/GraphQLSchemaAutoConfigurationTest.java @@ -4,11 +4,6 @@ import java.util.Map; -import graphql.GraphQL; -import graphql.Scalars; -import graphql.schema.GraphQLFieldDefinition; -import graphql.schema.GraphQLObjectType; -import graphql.schema.GraphQLSchema; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -18,6 +13,12 @@ import org.springframework.stereotype.Component; import org.springframework.test.context.junit4.SpringRunner; +import graphql.GraphQL; +import graphql.Scalars; +import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLSchema; + @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=WebEnvironment.NONE) public class GraphQLSchemaAutoConfigurationTest { @@ -87,6 +88,11 @@ public void contextLoads() { // then assertThat(result.toString()).isEqualTo("{hello=world}"); assertThat(result2.toString()).isEqualTo("{greet=hello world}"); + + assertThat(graphQLSchema.getQueryType()) + .extracting(GraphQLObjectType::getName, GraphQLObjectType::getDescription) + .containsExactly("GraphQLBooks", "GraphQL Books Schema Description"); + } diff --git a/graphql-jpa-query-autoconfigure/src/test/resources/application.yml b/graphql-jpa-query-autoconfigure/src/test/resources/application.yml new file mode 100644 index 000000000..97b45f456 --- /dev/null +++ b/graphql-jpa-query-autoconfigure/src/test/resources/application.yml @@ -0,0 +1,14 @@ +spring: + jpa: + hibernate.ddl-auto: create-drop + show-sql: true + h2: + console.enabled: true + + graphql: + jpa: + query: + name: GraphQLBooks + description: GraphQL Books Schema Description + enabled: true + path: /graphql \ No newline at end of file diff --git a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQuery.java b/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQuery.java deleted file mode 100644 index 2e3ce63ce..000000000 --- a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQuery.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.boot.autoconfigure; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import com.introproventures.graphql.jpa.query.boot.autoconfigure.GraphQLJpaQueryAutoConfiguration.DefaultGraphQLJpaQueryConfiguration; -import com.introproventures.graphql.jpa.query.boot.autoconfigure.GraphQLJpaQueryAutoConfiguration.GraphQLJpaQuerySchemaConfigurer; -import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.PropertySource; - -@Documented -@Retention( RUNTIME ) -@Target( TYPE ) -@Import({DefaultGraphQLJpaQueryConfiguration.class, GraphQLJpaQuerySchemaConfigurer.class}) -@PropertySource("classpath:/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties") -public @interface EnableGraphQLJpaQuery { - -} diff --git a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfiguration.java b/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfiguration.java index 5b63fe8fd..d4d755fb6 100644 --- a/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfiguration.java +++ b/graphql-jpa-query-boot-starter/src/main/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfiguration.java @@ -17,30 +17,25 @@ import javax.persistence.EntityManager; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + import com.introproventures.graphql.jpa.query.autoconfigure.GraphQLSchemaConfigurer; import com.introproventures.graphql.jpa.query.autoconfigure.GraphQLShemaRegistration; import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor; import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder; import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; + import graphql.GraphQL; import graphql.schema.GraphQLSchema; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; @Configuration -@PropertySource("classpath:/com/introproventures/graphql/jpa/query/boot/autoconfigure/default.properties") @ConditionalOnClass(GraphQL.class) -@ConditionalOnProperty(name="spring.graphql.jpa.query.enabled", havingValue="true", matchIfMissing=false) +@ConditionalOnProperty(name="spring.graphql.jpa.query.enabled", havingValue="true", matchIfMissing=true) public class GraphQLJpaQueryAutoConfiguration { @Configuration @@ -54,18 +49,13 @@ public GraphQLJpaQuerySchemaConfigurer(GraphQLSchemaBuilder graphQLSchemaBuilder @Override public void configure(GraphQLShemaRegistration registry) { - registry.register(graphQLSchemaBuilder.build()); } } @Configuration - @EnableConfigurationProperties(GraphQLJpaQueryProperties.class) - public static class DefaultGraphQLJpaQueryConfiguration implements ImportAware { + public static class DefaultGraphQLJpaQueryConfiguration { - @Autowired - GraphQLJpaQueryProperties properties; - @Bean @ConditionalOnMissingBean(GraphQLExecutor.class) public GraphQLExecutor graphQLExecutor(GraphQLSchema graphQLSchema) { @@ -75,17 +65,8 @@ public GraphQLExecutor graphQLExecutor(GraphQLSchema graphQLSchema) { @Bean @ConditionalOnMissingBean(GraphQLSchemaBuilder.class) public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) { - Assert.notNull(properties.getName(), "GraphQL schema name cannot be null."); - Assert.notNull(properties.getDescription(), "GraphQL schema description cannot be null."); - - return new GraphQLJpaSchemaBuilder(entityManager) - .name(properties.getName()) - .description(properties.getDescription()); + return new GraphQLJpaSchemaBuilder(entityManager); } - @Override - public void setImportMetadata(AnnotationMetadata importMetadata) { - properties.setEnabled(true); - } } } diff --git a/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQueryTest.java b/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQueryTest.java deleted file mode 100644 index 44d6d9079..000000000 --- a/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/EnableGraphQLJpaQueryTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.boot.autoconfigure; - -import static org.assertj.core.api.Assertions.assertThat; - -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.autoconfigure.domain.EntityScan; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor; -import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder; -import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor; -import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; -import com.introproventures.graphql.jpa.query.starter.model.Author; - -@RunWith(SpringRunner.class) -@SpringBootTest( - properties={"spring.graphql.jpa.query.enabled=false"}, - webEnvironment = WebEnvironment.RANDOM_PORT -) -public class EnableGraphQLJpaQueryTest { - - @SpringBootApplication(exclude=GraphQLJpaQueryAutoConfiguration.class) - @EntityScan(basePackageClasses=Author.class) - @EnableGraphQLJpaQuery - static class Application { - } - - @Autowired - GraphQLJpaQueryProperties graphQLJpaQueryProperties; - - @Autowired - GraphQLExecutor graphQLExecutor; - - @Autowired - GraphQLSchemaBuilder graphQLSchemaBuilder; - - @Test - public void contextIsConfigured() { - assertThat(graphQLExecutor).isInstanceOf(GraphQLJpaExecutor.class); - assertThat(graphQLSchemaBuilder).isInstanceOf(GraphQLJpaSchemaBuilder.class); - - assertThat(graphQLJpaQueryProperties.getName()).isEqualTo("GraphQLBooks"); - assertThat(graphQLJpaQueryProperties.getDescription()).isEqualTo("GraphQL Books Schema Description"); - assertThat(graphQLJpaQueryProperties.getPath()).isEqualTo("/graphql"); - assertThat(graphQLJpaQueryProperties.isEnabled()).isEqualTo(true); - - } - -} diff --git a/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfigurationTest.java b/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfigurationTest.java index 73b89d99c..189d47c3e 100644 --- a/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfigurationTest.java +++ b/graphql-jpa-query-boot-starter/src/test/java/com/introproventures/graphql/jpa/query/boot/autoconfigure/GraphQLJpaQueryAutoConfigurationTest.java @@ -32,6 +32,9 @@ import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder; import com.introproventures.graphql.jpa.query.starter.model.Author; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLSchema; + @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class GraphQLJpaQueryAutoConfigurationTest { @@ -41,24 +44,26 @@ public class GraphQLJpaQueryAutoConfigurationTest { static class Application { } - @Autowired - GraphQLJpaQueryProperties graphQLJpaQueryProperties; + @Autowired(required=false) + private GraphQLExecutor graphQLExecutor; - @Autowired - GraphQLExecutor graphQLExecutor; + @Autowired(required=false) + private GraphQLSchemaBuilder graphQLSchemaBuilder; @Autowired - GraphQLSchemaBuilder graphQLSchemaBuilder; + private GraphQLSchema graphQLSchema; @Test public void contextIsAutoConfigured() { - assertThat(graphQLExecutor).isInstanceOf(GraphQLJpaExecutor.class); - assertThat(graphQLSchemaBuilder).isInstanceOf(GraphQLJpaSchemaBuilder.class); + assertThat(graphQLExecutor).isNotNull() + .isInstanceOf(GraphQLJpaExecutor.class); + + assertThat(graphQLSchemaBuilder).isNotNull() + .isInstanceOf(GraphQLJpaSchemaBuilder.class); - assertThat(graphQLJpaQueryProperties.getName()).isEqualTo("GraphQLBooks"); - assertThat(graphQLJpaQueryProperties.getDescription()).isEqualTo("GraphQL Books Schema Description"); - assertThat(graphQLJpaQueryProperties.getPath()).isEqualTo("/graphql"); - assertThat(graphQLJpaQueryProperties.isEnabled()).isEqualTo(true); + assertThat(graphQLSchema.getQueryType()) + .extracting(GraphQLObjectType::getName, GraphQLObjectType::getDescription) + .containsExactly("GraphQLBooks", "GraphQL Books Schema Description"); } } \ No newline at end of file diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java index 7a00249b9..72947aabf 100644 --- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java +++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java @@ -106,7 +106,7 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder { private EntityManager entityManager; - private String name = "GraphQL JPA Schema"; + private String name = "GraphQLJPAQuery"; private String description = "GraphQL Schema for all entities in this JPA application"; From f94e2c0c8208d67e80f5b26a87e05bf6740c3587 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 22:41:36 -0700 Subject: [PATCH 5/8] [maven-release-plugin] Update CHANGELOG.md --- CHANGELOG.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2d80deb..f83e91c8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,25 @@ # Change Log -## 0.3.14-SNAPSHOT +## 0.3.14 +* fix: Configuration properties are ignored when merging bug (#88) [f838056](https://github.com/introproventures/graphql-jpa-query/commit/f838056009ca884d45e451b96a7a28dd8f9ea5a1) +* fix: upgrade to Spring Boot 2.1.3.RELEASE (#87) [ee0aa6c](https://github.com/introproventures/graphql-jpa-query/commit/ee0aa6c9ad5fead0f5a15e2133460fdebb9a0724) +* Refactor SchemaBuilder using Introspection (#86) [493f65d](https://github.com/introproventures/graphql-jpa-query/commit/493f65daa0e95d50a2ee8787af4444bcb365c2ed) +* support calcs fields and functions (#85) [1cbf29c](https://github.com/introproventures/graphql-jpa-query/commit/1cbf29c21d845d75c291ec4bafd5e13b7b27b21c) +* feat: add JPA @EmbeddedId support (#84) [0def68d](https://github.com/introproventures/graphql-jpa-query/commit/0def68d42c817858a2d5248d10c4c1d13fcd8ad2) +* Update README.md [ac75192](https://github.com/introproventures/graphql-jpa-query/commit/ac751922119f5f8159bcbf5d89069a584ade6a79) +* Update README.md [4d783e2](https://github.com/introproventures/graphql-jpa-query/commit/4d783e25683b0847705b911dcad1289ebe1b47b8) +* Update README.md [369e2b5](https://github.com/introproventures/graphql-jpa-query/commit/369e2b58964dbaa1d1dec4867f5524af6df948eb) +* Update README.md [a553ca6](https://github.com/introproventures/graphql-jpa-query/commit/a553ca626b46c292cc1f4d6fa7947b5f8ad8e89c) +* Update README.md [fe2b7ca](https://github.com/introproventures/graphql-jpa-query/commit/fe2b7ca8407f6421767e0c28ec7a40879c8f8fc7) +* Update README.md [25b140e](https://github.com/introproventures/graphql-jpa-query/commit/25b140ecd2fd0185adf535bfeaa94592d65d298a) +* Update README.md [8b16599](https://github.com/introproventures/graphql-jpa-query/commit/8b165996e872ee0872ed8c654461f2637332a7b1) +* fix: Clean up application.yaml configurations [b672e43](https://github.com/introproventures/graphql-jpa-query/commit/b672e437d68435e08862dc97438f8ae198fc9b5e) +* Update README.md [b83a22d](https://github.com/introproventures/graphql-jpa-query/commit/b83a22d3f82fd310f590364dc60a510e220094d8) +* Update README.md [8111ee4](https://github.com/introproventures/graphql-jpa-query/commit/8111ee4e1fe130cf4f8a89677709d069fad1e36a) +* Update README.md [f484e23](https://github.com/introproventures/graphql-jpa-query/commit/f484e2325cdf873cc5d65cd72a7d17053ddc2787) +* feat: Created example to merge two JPA data sources into one schema (#79) [12caf3a](https://github.com/introproventures/graphql-jpa-query/commit/12caf3a8ad8cee64932d1cbc1fa955888ccd5e14) +* Update README.md [ca18221](https://github.com/introproventures/graphql-jpa-query/commit/ca1822123c2e34fe7f50fe804a53f7367c841cda) +* Update README.md [dfaa0ed](https://github.com/introproventures/graphql-jpa-query/commit/dfaa0ed4e26d92f469e3eba6fa3e3062e125313d) * Extract graphql-jpa-query-web module from starter (#74) [8d72bbe](https://github.com/introproventures/graphql-jpa-query/commit/8d72bbee8d6aeb568604e7070d90c10657a766e4) * fix: configure gitHub url [b0839ca](https://github.com/introproventures/graphql-jpa-query/commit/b0839ca427b8a05efd5d4819a1ec2ac1f3b7ad2b) * fix: (version) update git-changelog-maven-plugin to 0.4.0 [7867ed4](https://github.com/introproventures/graphql-jpa-query/commit/7867ed417fb36f7d0d3e10b8f108397c1f816f53) From f4334235d80e501613c61faba092103e22274c00 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 22:43:08 -0700 Subject: [PATCH 6/8] [maven-release-plugin] prepare release 0.3.14 --- graphql-jpa-query-annotations/pom.xml | 2 +- graphql-jpa-query-autoconfigure/pom.xml | 2 +- graphql-jpa-query-boot-starter/pom.xml | 2 +- graphql-jpa-query-build/pom.xml | 2 +- graphql-jpa-query-dependencies/pom.xml | 2 +- graphql-jpa-query-example-merge/pom.xml | 2 +- graphql-jpa-query-example/pom.xml | 2 +- graphql-jpa-query-schema/pom.xml | 2 +- graphql-jpa-query-web/pom.xml | 2 +- pom.xml | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/graphql-jpa-query-annotations/pom.xml b/graphql-jpa-query-annotations/pom.xml index 06002c5a8..c756cf95c 100644 --- a/graphql-jpa-query-annotations/pom.xml +++ b/graphql-jpa-query-annotations/pom.xml @@ -6,7 +6,7 @@ com.introproventures graphql-jpa-query-dependencies - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-dependencies diff --git a/graphql-jpa-query-autoconfigure/pom.xml b/graphql-jpa-query-autoconfigure/pom.xml index c749bf258..f1e44273e 100644 --- a/graphql-jpa-query-autoconfigure/pom.xml +++ b/graphql-jpa-query-autoconfigure/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build graphql-jpa-query-autoconfigure diff --git a/graphql-jpa-query-boot-starter/pom.xml b/graphql-jpa-query-boot-starter/pom.xml index 7c5417be2..b7e20388c 100644 --- a/graphql-jpa-query-boot-starter/pom.xml +++ b/graphql-jpa-query-boot-starter/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build diff --git a/graphql-jpa-query-build/pom.xml b/graphql-jpa-query-build/pom.xml index 3e5d72b92..fbe5c487d 100644 --- a/graphql-jpa-query-build/pom.xml +++ b/graphql-jpa-query-build/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-dependencies - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-dependencies graphql-jpa-query-build diff --git a/graphql-jpa-query-dependencies/pom.xml b/graphql-jpa-query-dependencies/pom.xml index edc78514b..4719fc647 100644 --- a/graphql-jpa-query-dependencies/pom.xml +++ b/graphql-jpa-query-dependencies/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query - 0.3.14-SNAPSHOT + 0.3.14 .. graphql-jpa-query-dependencies diff --git a/graphql-jpa-query-example-merge/pom.xml b/graphql-jpa-query-example-merge/pom.xml index 93e5ac7e9..e6e6ab2aa 100644 --- a/graphql-jpa-query-example-merge/pom.xml +++ b/graphql-jpa-query-example-merge/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build diff --git a/graphql-jpa-query-example/pom.xml b/graphql-jpa-query-example/pom.xml index 02bb90b93..dbd72898b 100644 --- a/graphql-jpa-query-example/pom.xml +++ b/graphql-jpa-query-example/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build diff --git a/graphql-jpa-query-schema/pom.xml b/graphql-jpa-query-schema/pom.xml index b234442f8..db4060df6 100644 --- a/graphql-jpa-query-schema/pom.xml +++ b/graphql-jpa-query-schema/pom.xml @@ -5,7 +5,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build diff --git a/graphql-jpa-query-web/pom.xml b/graphql-jpa-query-web/pom.xml index 62ce436df..16981190a 100644 --- a/graphql-jpa-query-web/pom.xml +++ b/graphql-jpa-query-web/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14-SNAPSHOT + 0.3.14 ../graphql-jpa-query-build graphql-jpa-query-web diff --git a/pom.xml b/pom.xml index 251d4b363..5ba8507c8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.introproventures graphql-jpa-query - 0.3.14-SNAPSHOT + 0.3.14 pom @@ -62,7 +62,7 @@ scm:git:https://github.com/introproventures/graphql-jpa-query.git scm:git:git@github.com:introproventures/graphql-jpa-query.git https://github.com/introproventures/graphql-jpa-query - HEAD + 0.3.14 2017 From 15eddf89ebeadeb109170e3a96399149fd5e42c3 Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 22:43:22 -0700 Subject: [PATCH 7/8] [maven-release-plugin] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f83e91c8a..07dc1d330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## 0.3.14 +## 0.3.15-SNAPSHOT * fix: Configuration properties are ignored when merging bug (#88) [f838056](https://github.com/introproventures/graphql-jpa-query/commit/f838056009ca884d45e451b96a7a28dd8f9ea5a1) * fix: upgrade to Spring Boot 2.1.3.RELEASE (#87) [ee0aa6c](https://github.com/introproventures/graphql-jpa-query/commit/ee0aa6c9ad5fead0f5a15e2133460fdebb9a0724) * Refactor SchemaBuilder using Introspection (#86) [493f65d](https://github.com/introproventures/graphql-jpa-query/commit/493f65daa0e95d50a2ee8787af4444bcb365c2ed) From 6edb557e7145ddd91d76414ca439ed61de7d840d Mon Sep 17 00:00:00 2001 From: Igor Dianov Date: Sun, 10 Mar 2019 22:43:23 -0700 Subject: [PATCH 8/8] [maven-release-plugin] prepare for next development iteration --- graphql-jpa-query-annotations/pom.xml | 2 +- graphql-jpa-query-autoconfigure/pom.xml | 2 +- graphql-jpa-query-boot-starter/pom.xml | 2 +- graphql-jpa-query-build/pom.xml | 2 +- graphql-jpa-query-dependencies/pom.xml | 2 +- graphql-jpa-query-example-merge/pom.xml | 2 +- graphql-jpa-query-example/pom.xml | 2 +- graphql-jpa-query-schema/pom.xml | 2 +- graphql-jpa-query-web/pom.xml | 2 +- pom.xml | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/graphql-jpa-query-annotations/pom.xml b/graphql-jpa-query-annotations/pom.xml index c756cf95c..96d85c003 100644 --- a/graphql-jpa-query-annotations/pom.xml +++ b/graphql-jpa-query-annotations/pom.xml @@ -6,7 +6,7 @@ com.introproventures graphql-jpa-query-dependencies - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-dependencies diff --git a/graphql-jpa-query-autoconfigure/pom.xml b/graphql-jpa-query-autoconfigure/pom.xml index f1e44273e..9e343bcd4 100644 --- a/graphql-jpa-query-autoconfigure/pom.xml +++ b/graphql-jpa-query-autoconfigure/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build graphql-jpa-query-autoconfigure diff --git a/graphql-jpa-query-boot-starter/pom.xml b/graphql-jpa-query-boot-starter/pom.xml index b7e20388c..7ee843eab 100644 --- a/graphql-jpa-query-boot-starter/pom.xml +++ b/graphql-jpa-query-boot-starter/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build diff --git a/graphql-jpa-query-build/pom.xml b/graphql-jpa-query-build/pom.xml index fbe5c487d..971d801f3 100644 --- a/graphql-jpa-query-build/pom.xml +++ b/graphql-jpa-query-build/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-dependencies - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-dependencies graphql-jpa-query-build diff --git a/graphql-jpa-query-dependencies/pom.xml b/graphql-jpa-query-dependencies/pom.xml index 4719fc647..25408b399 100644 --- a/graphql-jpa-query-dependencies/pom.xml +++ b/graphql-jpa-query-dependencies/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query - 0.3.14 + 0.3.15-SNAPSHOT .. graphql-jpa-query-dependencies diff --git a/graphql-jpa-query-example-merge/pom.xml b/graphql-jpa-query-example-merge/pom.xml index e6e6ab2aa..49f2f11c0 100644 --- a/graphql-jpa-query-example-merge/pom.xml +++ b/graphql-jpa-query-example-merge/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build diff --git a/graphql-jpa-query-example/pom.xml b/graphql-jpa-query-example/pom.xml index dbd72898b..c08448a6b 100644 --- a/graphql-jpa-query-example/pom.xml +++ b/graphql-jpa-query-example/pom.xml @@ -7,7 +7,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build diff --git a/graphql-jpa-query-schema/pom.xml b/graphql-jpa-query-schema/pom.xml index db4060df6..ed7f8bd6a 100644 --- a/graphql-jpa-query-schema/pom.xml +++ b/graphql-jpa-query-schema/pom.xml @@ -5,7 +5,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build diff --git a/graphql-jpa-query-web/pom.xml b/graphql-jpa-query-web/pom.xml index 16981190a..dc361fd84 100644 --- a/graphql-jpa-query-web/pom.xml +++ b/graphql-jpa-query-web/pom.xml @@ -3,7 +3,7 @@ com.introproventures graphql-jpa-query-build - 0.3.14 + 0.3.15-SNAPSHOT ../graphql-jpa-query-build graphql-jpa-query-web diff --git a/pom.xml b/pom.xml index 5ba8507c8..95f1b61c7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.introproventures graphql-jpa-query - 0.3.14 + 0.3.15-SNAPSHOT pom @@ -62,7 +62,7 @@ scm:git:https://github.com/introproventures/graphql-jpa-query.git scm:git:git@github.com:introproventures/graphql-jpa-query.git https://github.com/introproventures/graphql-jpa-query - 0.3.14 + HEAD 2017