Skip to content

Commit e15ac84

Browse files
Generate jackson type id resolver annotation (#637)
* Generate Jackson resolver annotation on union interface * Generate Jackson resolver (Java only) * plug with gradle plugin & some fixes * plug with maven plugin * fix issue when model package was null or empty * fix codestyle issue * handle model name prefix & suffix * support scala jackson-typeid annotations support scala jackosn enum annotation * support scala jackson-typeid annotations support scala jackosn enum annotation * codefix * fix bug * fix bug * codestyle fix * fix ci test * fix checkstyle * fix ci test * refactor duplicated code in *GraphQLTypeMapper * add GraphQLTypeMapper methods javadoc * remove unecessary import * refactor to use definition Co-authored-by: 梦境迷离 <dreamylost@outlook.com> Co-authored-by: 梦境迷离 <568845948@qq.com>
1 parent 94a8357 commit e15ac84

File tree

62 files changed

+1211
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1211
-8
lines changed

docs/codegen-options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. |
1919
| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. |
2020
| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
21+
| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
2122
| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). |
2223
| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). |
2324
| `apiInterfaceStrategy` | *See<br>[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* |

plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
8383
private Boolean useOptionalForNullableReturnTypes = MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES;
8484
private Boolean generateApisWithThrowsException = MappingConfigConstants.DEFAULT_GENERATE_APIS_WITH_THROWS_EXCEPTION;
8585
private Boolean addGeneratedAnnotation = MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION;
86+
private Boolean generateJacksonTypeIdResolver = MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER;
8687
private Set<String> fieldsWithResolvers = new HashSet<>();
8788
private Set<String> fieldsWithoutResolvers = new HashSet<>();
8889
private Set<String> typesAsInterfaces = new HashSet<>();
@@ -144,6 +145,7 @@ public void generate() throws Exception {
144145
mappingConfig.setUseOptionalForNullableReturnTypes(useOptionalForNullableReturnTypes);
145146
mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
146147
mappingConfig.setAddGeneratedAnnotation(addGeneratedAnnotation);
148+
mappingConfig.setGenerateJacksonTypeIdResolver(generateJacksonTypeIdResolver);
147149
mappingConfig.setApiReturnType(apiReturnType);
148150
mappingConfig.setApiReturnListType(apiReturnListType);
149151
mappingConfig.setSubscriptionReturnType(subscriptionReturnType);
@@ -634,6 +636,17 @@ public void setAddGeneratedAnnotation(Boolean addGeneratedAnnotation) {
634636
this.addGeneratedAnnotation = addGeneratedAnnotation;
635637
}
636638

639+
@Input
640+
@Optional
641+
@Override
642+
public Boolean getGenerateJacksonTypeIdResolver() {
643+
return generateJacksonTypeIdResolver;
644+
}
645+
646+
public void setGenerateJacksonTypeIdResolver(Boolean generateJacksonTypeIdResolver) {
647+
this.generateJacksonTypeIdResolver = generateJacksonTypeIdResolver;
648+
}
649+
637650
@Input
638651
@Optional
639652
@Override

plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
152152
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION_STRING)
153153
private boolean addGeneratedAnnotation;
154154

155+
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER_STRING)
156+
private boolean generateJacksonTypeIdResolver;
157+
155158
@Parameter
156159
private String[] fieldsWithResolvers;
157160

@@ -242,6 +245,7 @@ public void execute() throws MojoExecutionException {
242245
mappingConfig.setUseOptionalForNullableReturnTypes(useOptionalForNullableReturnTypes);
243246
mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
244247
mappingConfig.setAddGeneratedAnnotation(addGeneratedAnnotation);
248+
mappingConfig.setGenerateJacksonTypeIdResolver(generateJacksonTypeIdResolver);
245249
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
246250
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
247251
mappingConfig.setRelayConfig(relayConfig);
@@ -494,6 +498,11 @@ public Boolean getAddGeneratedAnnotation() {
494498
return addGeneratedAnnotation;
495499
}
496500

501+
@Override
502+
public Boolean getGenerateJacksonTypeIdResolver() {
503+
return generateJacksonTypeIdResolver;
504+
}
505+
497506
@Override
498507
public ApiRootInterfaceStrategy getApiRootInterfaceStrategy() {
499508
return apiRootInterfaceStrategy;

plugins/sbt/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ customAnnotationsMapping := {
4747
mapping.put("Character", annotations)
4848
// Note: only for Scala, please pay attention here, codegen have not generated `EpisodeDOTypeRefer.scala` class, so you should create it.
4949
// Since, 4.1.3, support to generate it.
50+
// Since, 5.0.1, It will be done automatically, no need to add this.
5051
mapping.put("Droid.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.model.EpisodeDOTypeRefer])"))
5152
mapping.put("Human.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.model.EpisodeDOTypeRefer])"))
5253
mapping

plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenKeys.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ trait GraphQLCodegenKeys {
124124

125125
val generateModelOpenClasses = settingKey[Boolean]("The class type of the generated model. If true, generate normal classes, else generate case class.")
126126

127+
val generateJacksonTypeIdResolver = settingKey[Boolean]("Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package")
128+
127129
//for version
128130
val javaxValidationApiVersion = settingKey[Option[String]]("javax-validation-api version")
129131
val graphqlJavaCodegenVersion = settingKey[Option[String]]("graphql java codegen version")

plugins/sbt/graphql-java-codegen-sbt-plugin/src/main/scala/io/github/dreamylost/graphql/codegen/GraphQLCodegenPlugin.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
6363
configurationFiles := Seq.empty[String],
6464
graphqlSchemaPaths := Seq.empty,
6565
graphqlSchemaValidate := Seq.empty,
66+
generateJacksonTypeIdResolver := MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER,
6667
customTypesMapping := new JHashMap[String, String](), //TODO use scala Map, convert to java Map
6768
customAnnotationsMapping := new JHashMap[String, JList[String]](),
6869
directiveAnnotationsMapping := new JHashMap[String, JList[String]](),
@@ -169,6 +170,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
169170
mappingConfig.setRelayConfig((relayConfig in GraphQLCodegenConfig).value)
170171
mappingConfig.setGeneratedLanguage((generatedLanguage in GraphQLCodegenConfig).value)
171172
mappingConfig.setGenerateModelOpenClasses((generateModelOpenClasses in GraphQLCodegenConfig).value)
173+
mappingConfig.setGenerateJacksonTypeIdResolver((generateJacksonTypeIdResolver in GraphQLCodegenConfig).value);
172174
mappingConfig
173175
}
174176

plugins/sbt/graphql-java-codegen-sbt-plugin/src/sbt-test/graphql-codegen-sbt-plugin/example-client-scala/build.sbt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ customAnnotationsMapping := {
3434
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[HumanDO], name = "Human"),
3535
| new com.fasterxml.jackson.annotation.JsonSubTypes.Type(value = classOf[DroidDO], name = "Droid")))""".stripMargin)
3636
mapping.put("Character", annotations)
37-
mapping.put("Droid.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.model.EpisodeDOTypeRefer])"))
38-
mapping.put("Human.appearsIn", util.Arrays.asList("@com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[io.github.dreamylost.model.EpisodeDOTypeRefer])"))
3937
mapping
4038
}
4139
generateCodegenTargetPath in GraphQLCodegenConfig := crossTarget.value / "src_managed_graphql_scala"

src/main/java/com/kobylynskyi/graphql/codegen/FreeMarkerTemplateType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ enum FreeMarkerTemplateType {
1010
INTERFACE,
1111
OPERATIONS,
1212
PARAMETRIZED_INPUT,
13-
RESPONSE_PROJECTION;
13+
RESPONSE_PROJECTION,
14+
JACKSON_TYPE_ID_RESOLVER;
1415

1516
}

src/main/java/com/kobylynskyi/graphql/codegen/FreeMarkerTemplatesRegistry.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.ENUM;
1717
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.INTERFACE;
18+
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.JACKSON_TYPE_ID_RESOLVER;
1819
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.OPERATIONS;
1920
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.PARAMETRIZED_INPUT;
2021
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.REQUEST;
@@ -61,6 +62,8 @@ class FreeMarkerTemplatesRegistry {
6162
configuration.getTemplate("templates/java-lang/javaClassGraphqlParametrizedInput.ftl"));
6263
javaTemplates.put(RESPONSE_PROJECTION,
6364
configuration.getTemplate("templates/java-lang/javaClassGraphqlResponseProjection.ftl"));
65+
javaTemplates.put(JACKSON_TYPE_ID_RESOLVER,
66+
configuration.getTemplate("templates/java-lang/javaClassGraphqlJacksonTypeIdResolver.ftl"));
6467
templateMap.put(GeneratedLanguage.JAVA, javaTemplates);
6568

6669
EnumMap<FreeMarkerTemplateType, Template> scalaTemplates = new EnumMap<>(FreeMarkerTemplateType.class);
@@ -82,6 +85,8 @@ class FreeMarkerTemplatesRegistry {
8285
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlParametrizedInput.ftl"));
8386
scalaTemplates.put(RESPONSE_PROJECTION,
8487
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlResponseProjection.ftl"));
88+
scalaTemplates.put(JACKSON_TYPE_ID_RESOLVER,
89+
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlJacksonTypeIdResolver.ftl"));
8590
templateMap.put(GeneratedLanguage.SCALA, scalaTemplates);
8691

8792
EnumMap<FreeMarkerTemplateType, Template> kotlinTemplates = new EnumMap<>(FreeMarkerTemplateType.class);
@@ -103,6 +108,8 @@ class FreeMarkerTemplatesRegistry {
103108
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlParametrizedInput.ftl"));
104109
kotlinTemplates.put(RESPONSE_PROJECTION,
105110
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlResponseProjection.ftl"));
111+
kotlinTemplates.put(JACKSON_TYPE_ID_RESOLVER,
112+
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlJacksonTypeIdResolver.ftl"));
106113
templateMap.put(GeneratedLanguage.KOTLIN, kotlinTemplates);
107114
} catch (IOException e) {
108115
throw new UnableToLoadFreeMarkerTemplateException(e);

src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.kobylynskyi.graphql.codegen;
22

3+
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
34
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
45
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
56
import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy;
@@ -28,10 +29,17 @@
2829
import java.util.ArrayList;
2930
import java.util.Collection;
3031
import java.util.Collections;
32+
import java.util.HashMap;
3133
import java.util.List;
3234
import java.util.Map;
3335
import java.util.Optional;
3436

37+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.CLASS_NAME;
38+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.GENERATED_ANNOTATION;
39+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.GENERATED_INFO;
40+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.MODEL_NAME_PREFIX;
41+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.MODEL_NAME_SUFFIX;
42+
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.PACKAGE;
3543
import static java.util.stream.Collectors.toList;
3644

3745
/**
@@ -185,6 +193,10 @@ protected void initDefaultValues(MappingConfig mappingConfig) {
185193
if (mappingConfig.getAddGeneratedAnnotation() == null) {
186194
mappingConfig.setAddGeneratedAnnotation(MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION);
187195
}
196+
if (mappingConfig.getGenerateJacksonTypeIdResolver() == null) {
197+
mappingConfig.setGenerateJacksonTypeIdResolver(
198+
MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER);
199+
}
188200
if (mappingConfig.getUseOptionalForNullableReturnTypes() == null) {
189201
mappingConfig.setUseOptionalForNullableReturnTypes(
190202
MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES);
@@ -313,6 +325,9 @@ private List<File> processDefinitions(ExtendedDocument document) {
313325
for (ExtendedInterfaceTypeDefinition definition : document.getInterfaceDefinitions()) {
314326
generateFieldResolver(context, definition.getFieldDefinitions(), definition).ifPresent(generatedFiles::add);
315327
}
328+
if (Boolean.TRUE.equals(mappingConfig.getGenerateJacksonTypeIdResolver())) {
329+
generatedFiles.add(generateJacksonTypeIdResolver(context));
330+
}
316331
System.out.printf("Generated %d definition classes in folder %s%n", generatedFiles.size(),
317332
outputDir.getAbsolutePath());
318333
return generatedFiles;
@@ -534,6 +549,18 @@ private File generateEnum(MappingContext mappingContext, ExtendedEnumTypeDefinit
534549
.generateFile(mappingContext, FreeMarkerTemplateType.ENUM, dataModel, outputDir);
535550
}
536551

552+
private File generateJacksonTypeIdResolver(MappingContext context) {
553+
Map<String, Object> dataModel = new HashMap<>();
554+
dataModel.put(PACKAGE, DataModelMapper.getModelPackageName(context));
555+
dataModel.put(MODEL_NAME_PREFIX, context.getModelNamePrefix());
556+
dataModel.put(MODEL_NAME_SUFFIX, context.getModelNameSuffix());
557+
dataModel.put(CLASS_NAME, "GraphqlJacksonTypeIdResolver");
558+
dataModel.put(GENERATED_ANNOTATION, context.getAddGeneratedAnnotation());
559+
dataModel.put(GENERATED_INFO, context.getGeneratedInformation());
560+
return GraphQLCodegenFileCreator
561+
.generateFile(context, FreeMarkerTemplateType.JACKSON_TYPE_ID_RESOLVER, dataModel, outputDir);
562+
}
563+
537564
protected void initCustomTypeMappings(Collection<ExtendedScalarTypeDefinition> scalarTypeDefinitions) {
538565
for (ExtendedScalarTypeDefinition definition : scalarTypeDefinitions) {
539566
if (definition.getDefinition() != null) {

0 commit comments

Comments
 (0)