diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java index d15ddf51d..e31003126 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java @@ -95,6 +95,9 @@ private String recursionCheckedFields(TypeInfo type) { } private String fieldsFragment(TypeInfo typeInfo) { + if (typeInfo.fields().findAny().isEmpty()) { + return ""; + } return "... on " + typeInfo.getGraphQlTypeName() + fields(typeInfo); } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java index 6fe59755f..0b4d009da 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java @@ -441,6 +441,9 @@ private String makeFirstLetterUppercase(String value) { } private String fieldsFragment(TypeModel type) { + if (type.fields().findAny().isEmpty()) { + return ""; + } return "... on " + type.getGraphQlTypeName() + fields(type); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java index f4e691d88..e3bcd02c7 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java @@ -42,11 +42,34 @@ String getMessage() { } } + @Union + @JsonbTypeInfo(key = "__typename", value = { + @JsonbSubtype(alias = "Data", type = Data.class), + @JsonbSubtype(alias = "Hidden", type = Hidden.class), + }) + public interface DetailsResponse { + } + + @Type("SuperHeroDetailsData") + public static class Data implements DetailsResponse { + String data; + + String getData() { + return data; + } + } + + @Type("SuperHeroDetailsHidden") + public static class Hidden implements DetailsResponse { + } + @GraphQLClientApi interface UnionApi { SuperHeroResponse find(String name); List findAll(String name); + + List details(String name); } @Test @@ -118,4 +141,27 @@ void shouldUnionFindAll() { then(response.get(1)).isInstanceOf(NotFound.class); then(((NotFound) response.get(1)).getMessage()).isEqualTo("The Nobody"); } + + @Test + void shouldSkipEmptyTypes() { + fixture.returnsData("'details':[" + + "{'__typename':'SuperHeroDetailsData','data':'Speed'}," + + "{'__typename':'SuperHeroDetailsData','data':'Agility'}," + + "{'__typename':'SuperHeroDetailsHidden'}" + + "]"); + var api = fixture.build(UnionApi.class); + + var response = api.details("Spider-Man"); + + then(fixture.query()).isEqualTo("query details($name: String) { details(name: $name){" + + "__typename " + + "... on SuperHeroDetailsData {data} } }"); + then(fixture.variables()).isEqualTo("{'name':'Spider-Man'}"); + then(response).hasSize(3); + then(response.get(0)).isInstanceOf(Data.class); + then(((Data) response.get(0)).getData()).isEqualTo("Speed"); + then(response.get(1)).isInstanceOf(Data.class); + then(((Data) response.get(1)).getData()).isEqualTo("Agility"); + then(response.get(2)).isInstanceOf(Hidden.class); + } }