diff --git a/graphql-builder/src/main/java/com/phocassoftware/graphql/builder/TypeBuilder.java b/graphql-builder/src/main/java/com/phocassoftware/graphql/builder/TypeBuilder.java index a57e1af2..f787200b 100644 --- a/graphql-builder/src/main/java/com/phocassoftware/graphql/builder/TypeBuilder.java +++ b/graphql-builder/src/main/java/com/phocassoftware/graphql/builder/TypeBuilder.java @@ -198,33 +198,37 @@ public Record(EntityProcessor entityProcessor, TypeMeta meta) { protected void processFields(String typeName, Builder graphType, graphql.schema.GraphQLInterfaceType.Builder interfaceBuilder) { var type = meta.getType(); - var methods = Arrays + var fieldsByName = Arrays .stream(type.getDeclaredFields()) .filter(field -> !field.isSynthetic()) - .filter(field -> !field.getDeclaringClass().equals(Object.class)) - .filter(field -> !field.isAnnotationPresent(GraphQLIgnore.class)) - .filter(field -> !Modifier.isAbstract(field.getModifiers())) - .filter(field -> !field.getDeclaringClass().isInterface()) .filter(field -> !Modifier.isStatic(field.getModifiers())) - .toList(); + .collect(java.util.stream.Collectors.toMap(f -> f.getName(), f -> f, (a, b) -> a)); var duplicateMethodNames = new HashSet(); - methods.forEach(field -> { - try { - var method = type.getMethod(field.getName()); - if (method.isAnnotationPresent(GraphQLIgnore.class)) return; - var name = EntityUtil.getName(field.getName(), field, method); + Arrays + .stream(type.getMethods()) + .filter(method -> !method.isSynthetic()) + .filter(method -> !method.getDeclaringClass().equals(Object.class)) + .filter(method -> !method.isAnnotationPresent(GraphQLIgnore.class)) + .filter(method -> !Modifier.isStatic(method.getModifiers())) + .filter(method -> !method.getReturnType().equals(void.class)) + .filter(method -> !method.getName().startsWith("get") && !method.getName().startsWith("is")) + .forEach(method -> { + var field = fieldsByName.get(method.getName()); + if (field != null && field.isAnnotationPresent(GraphQLIgnore.class)) { + return; + } + var name = field != null + ? EntityUtil.getName(field.getName(), field, method) + : method.getName(); if (!duplicateMethodNames.add(name)) { throw new DuplicateMethodNameException(typeName, name); } var f = entityProcessor.getMethodProcessor().process(null, FieldCoordinates.coordinates(typeName, name), meta, method); graphType.field(f); interfaceBuilder.field(f); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Failed to process method " + field, e); - } - }); + }); } } } diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/.DS_Store b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/.DS_Store new file mode 100644 index 00000000..ed2f4996 Binary files /dev/null and b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/.DS_Store differ diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/RecordTest.java b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/RecordTest.java index 15b03d64..165cc659 100644 --- a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/RecordTest.java +++ b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/RecordTest.java @@ -30,9 +30,29 @@ //does not test all of records as needs newer version of java. But Classes that look like records public class RecordTest { + @Test + public void testRecordInheritance() { + var response = execute( + "query { recordInheritanceTest { ... on CatRecord { name, somethingToDoWithCats, type, greet(greeting: \"Hello\") } ... on DogRecord { name, somethingToDoWithDogs, type } } }", + null + ); + assertTrue(response.getErrors().isEmpty(), () -> response.getErrors().toString()); + Map>> data = response.getData(); + var results = data.get("recordInheritanceTest"); + assertEquals(2, results.size()); + assertEquals(Map.of("name", "Lola", "somethingToDoWithDogs", "LikesBones", "type", "Dog"), results.get(0)); + assertEquals(Map.of("name", "Mavi", "somethingToDoWithCats", "LikesCheese", "type", "Cat", "greet", "Hello Mavi"), results.get(1)); + } + @Test public void testEntireContext() { - var type = Map.of("name", "foo", "age", 4); + var type = Map + .of( + "name", + "foo", + "age", + 4 + ); Map> response = execute( "query passthrough($type: InputTypeInput!){passthrough(type: $type) {name age weight}} ", Map.of("type", type) diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/AnimalInterface.java b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/AnimalInterface.java new file mode 100644 index 00000000..5ee5ca87 --- /dev/null +++ b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/AnimalInterface.java @@ -0,0 +1,39 @@ +/* + * 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.phocassoftware.graphql.builder.record; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonSubTypes; + +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRecord.class, name = "Cat"), + @JsonSubTypes.Type(value = DogRecord.class, name = "Dog"), +}) +public sealed interface AnimalInterface + permits CatRecord, DogRecord { + + String name(); + + Optional description(); + + AnimalType type(); + + enum AnimalType { + @JsonProperty("Cat") + Cat, + @JsonProperty("Dog") + Dog + } +} diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/CatRecord.java b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/CatRecord.java new file mode 100644 index 00000000..35ce3bb8 --- /dev/null +++ b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/CatRecord.java @@ -0,0 +1,28 @@ +/* + * 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.phocassoftware.graphql.builder.record; + +import java.util.Optional; + +public record CatRecord( + String name, + String somethingToDoWithCats, + Optional description +) implements AnimalInterface { + public AnimalType type() { + return AnimalType.Cat; + } + + public String greet(String greeting) { + return greeting + " " + name; + } +} \ No newline at end of file diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/DogRecord.java b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/DogRecord.java new file mode 100644 index 00000000..52fb36de --- /dev/null +++ b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/DogRecord.java @@ -0,0 +1,25 @@ +/* + * 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.phocassoftware.graphql.builder.record; + +import java.util.Optional; + +public record DogRecord( + String name, + String somethingToDoWithDogs, + Optional description +) implements AnimalInterface { + @Override + public AnimalType type() { + return AnimalType.Dog; + } +} \ No newline at end of file diff --git a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/Queries.java b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/Queries.java index 51ba846c..37078e52 100644 --- a/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/Queries.java +++ b/graphql-builder/src/test/java/com/phocassoftware/graphql/builder/record/Queries.java @@ -14,6 +14,8 @@ import com.phocassoftware.graphql.builder.annotations.GraphQLDescription; import com.phocassoftware.graphql.builder.annotations.InnerNullable; import com.phocassoftware.graphql.builder.annotations.Query; +import com.phocassoftware.graphql.builder.annotations.Union; + import java.util.List; import java.util.Optional; import javax.annotation.Nullable; @@ -48,6 +50,16 @@ public static List> nullableInnerArrayTest(List recordInheritanceTest() { + return List.of(new DogRecord("Lola", "LikesBones", Optional.of("fluffy")), new CatRecord("Mavi", "LikesCheese", Optional.of("Angry"))); + } + @GraphQLDescription("record Type") - static final record InputType(@GraphQLDescription("the name") String name, int age, Optional weight) {} + static final record InputType( + @GraphQLDescription("the name") String name, + int age, + Optional weight + ) {} }