Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4b5e864
Generate Jackson resolver annotation on union interface
gdhordain Apr 8, 2021
530ee42
Generate Jackson resolver (Java only)
gdhordain Apr 8, 2021
e457953
plug with gradle plugin & some fixes
gdhordain Apr 8, 2021
14cb716
plug with maven plugin
gdhordain Apr 8, 2021
ae59ca8
fix issue when model package was null or empty
gdhordain Apr 9, 2021
984259d
fix codestyle issue
gdhordain Apr 9, 2021
00638ca
handle model name prefix & suffix
gdhordain Apr 9, 2021
69b8973
support scala jackson-typeid annotations
jxnu-liguobin Apr 10, 2021
b006e40
support scala jackson-typeid annotations
jxnu-liguobin Apr 10, 2021
67ee2b6
codefix
jxnu-liguobin Apr 10, 2021
1ff4736
fix bug
jxnu-liguobin Apr 10, 2021
58ad4f9
fix bug
jxnu-liguobin Apr 10, 2021
253f648
codestyle fix
jxnu-liguobin Apr 10, 2021
0a1dabb
Merge pull request #1 from jxnu-liguobin/support-scala-jackosn-enum-a…
gdhordain Apr 12, 2021
1737720
fix ci test
jxnu-liguobin Apr 12, 2021
4578f89
Merge pull request #2 from jxnu-liguobin/generate-jackson-type-id-res…
gdhordain Apr 12, 2021
2211558
fix checkstyle
gdhordain Apr 12, 2021
4062b26
fix ci test
jxnu-liguobin Apr 12, 2021
2547d86
Merge pull request #3 from jxnu-liguobin/generate-jackson-type-id-res…
gdhordain Apr 12, 2021
9283ae6
refactor duplicated code in *GraphQLTypeMapper
gdhordain Apr 14, 2021
9081631
add GraphQLTypeMapper methods javadoc
gdhordain Apr 14, 2021
3d15a86
remove unecessary import
gdhordain Apr 16, 2021
05a5840
refactor to use definition
gdhordain Apr 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/codegen-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. |
| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. |
| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). |
| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). |
| `apiInterfaceStrategy` | *See<br>[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
private Boolean useOptionalForNullableReturnTypes = MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES;
private Boolean generateApisWithThrowsException = MappingConfigConstants.DEFAULT_GENERATE_APIS_WITH_THROWS_EXCEPTION;
private Boolean addGeneratedAnnotation = MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION;
private Boolean generateJacksonTypeIdResolver = MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER;
private Set<String> fieldsWithResolvers = new HashSet<>();
private Set<String> fieldsWithoutResolvers = new HashSet<>();
private Set<String> typesAsInterfaces = new HashSet<>();
Expand Down Expand Up @@ -143,6 +144,7 @@ public void generate() throws Exception {
mappingConfig.setUseOptionalForNullableReturnTypes(useOptionalForNullableReturnTypes);
mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
mappingConfig.setAddGeneratedAnnotation(addGeneratedAnnotation);
mappingConfig.setGenerateJacksonTypeIdResolver(generateJacksonTypeIdResolver);
mappingConfig.setApiReturnType(apiReturnType);
mappingConfig.setApiReturnListType(apiReturnListType);
mappingConfig.setSubscriptionReturnType(subscriptionReturnType);
Expand Down Expand Up @@ -632,6 +634,17 @@ public void setAddGeneratedAnnotation(Boolean addGeneratedAnnotation) {
this.addGeneratedAnnotation = addGeneratedAnnotation;
}

@Input
@Optional
@Override
public Boolean getGenerateJacksonTypeIdResolver() {
return generateJacksonTypeIdResolver;
}

public void setGenerateJacksonTypeIdResolver(Boolean generateJacksonTypeIdResolver) {
this.generateJacksonTypeIdResolver = generateJacksonTypeIdResolver;
}

@Input
@Optional
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION_STRING)
private boolean addGeneratedAnnotation;

@Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER_STRING)
private boolean generateJacksonTypeIdResolver;

@Parameter
private String[] fieldsWithResolvers;

Expand Down Expand Up @@ -239,6 +242,7 @@ public void execute() throws MojoExecutionException {
mappingConfig.setUseOptionalForNullableReturnTypes(useOptionalForNullableReturnTypes);
mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
mappingConfig.setAddGeneratedAnnotation(addGeneratedAnnotation);
mappingConfig.setGenerateJacksonTypeIdResolver(generateJacksonTypeIdResolver);
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
mappingConfig.setRelayConfig(relayConfig);
Expand Down Expand Up @@ -490,6 +494,11 @@ public Boolean getAddGeneratedAnnotation() {
return addGeneratedAnnotation;
}

@Override
public Boolean getGenerateJacksonTypeIdResolver() {
return generateJacksonTypeIdResolver;
}

@Override
public ApiRootInterfaceStrategy getApiRootInterfaceStrategy() {
return apiRootInterfaceStrategy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum FreeMarkerTemplateType {
INTERFACE,
OPERATIONS,
PARAMETRIZED_INPUT,
RESPONSE_PROJECTION;
RESPONSE_PROJECTION,
JACKSON_TYPE_ID_RESOLVER;

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.ENUM;
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.INTERFACE;
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.JACKSON_TYPE_ID_RESOLVER;
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.OPERATIONS;
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.PARAMETRIZED_INPUT;
import static com.kobylynskyi.graphql.codegen.FreeMarkerTemplateType.REQUEST;
Expand Down Expand Up @@ -58,6 +59,8 @@ class FreeMarkerTemplatesRegistry {
configuration.getTemplate("templates/java-lang/javaClassGraphqlParametrizedInput.ftl"));
javaTemplates.put(RESPONSE_PROJECTION,
configuration.getTemplate("templates/java-lang/javaClassGraphqlResponseProjection.ftl"));
javaTemplates.put(JACKSON_TYPE_ID_RESOLVER,
configuration.getTemplate("templates/java-lang/javaClassGraphqlJacksonTypeIdResolver.ftl"));
templateMap.put(GeneratedLanguage.JAVA, javaTemplates);

EnumMap<FreeMarkerTemplateType, Template> scalaTemplates = new EnumMap<>(FreeMarkerTemplateType.class);
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen;

import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy;
Expand Down Expand Up @@ -28,10 +29,17 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.kobylynskyi.graphql.codegen.model.DataModelFields.CLASS_NAME;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.GENERATED_ANNOTATION;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.GENERATED_INFO;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.MODEL_NAME_PREFIX;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.MODEL_NAME_SUFFIX;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.PACKAGE;
import static java.util.stream.Collectors.toList;

/**
Expand Down Expand Up @@ -185,6 +193,10 @@ protected void initDefaultValues(MappingConfig mappingConfig) {
if (mappingConfig.getAddGeneratedAnnotation() == null) {
mappingConfig.setAddGeneratedAnnotation(MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION);
}
if (mappingConfig.getGenerateJacksonTypeIdResolver() == null) {
mappingConfig.setGenerateJacksonTypeIdResolver(
MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER);
}
if (mappingConfig.getUseOptionalForNullableReturnTypes() == null) {
mappingConfig.setUseOptionalForNullableReturnTypes(
MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES);
Expand Down Expand Up @@ -310,6 +322,9 @@ private List<File> processDefinitions(ExtendedDocument document) {
for (ExtendedInterfaceTypeDefinition definition : document.getInterfaceDefinitions()) {
generateFieldResolver(context, definition.getFieldDefinitions(), definition).ifPresent(generatedFiles::add);
}
if (Boolean.TRUE.equals(mappingConfig.getGenerateJacksonTypeIdResolver())) {
generatedFiles.add(generateJacksonTypeIdResolver(context));
}
System.out.printf("Generated %d definition classes in folder %s%n", generatedFiles.size(),
outputDir.getAbsolutePath());
return generatedFiles;
Expand Down Expand Up @@ -531,6 +546,18 @@ private File generateEnum(MappingContext mappingContext, ExtendedEnumTypeDefinit
.generateFile(mappingContext, FreeMarkerTemplateType.ENUM, dataModel, outputDir);
}

private File generateJacksonTypeIdResolver(MappingContext context) {
Map<String, Object> dataModel = new HashMap<>();
dataModel.put(PACKAGE, DataModelMapper.getModelPackageName(context));
dataModel.put(MODEL_NAME_PREFIX, context.getModelNamePrefix());
dataModel.put(MODEL_NAME_SUFFIX, context.getModelNameSuffix());
dataModel.put(CLASS_NAME, "GraphqlJacksonTypeIdResolver");
dataModel.put(GENERATED_ANNOTATION, context.getAddGeneratedAnnotation());
dataModel.put(GENERATED_INFO, context.getGeneratedInformation());
return GraphQLCodegenFileCreator
.generateFile(context, FreeMarkerTemplateType.JACKSON_TYPE_ID_RESOLVER, dataModel, outputDir);
}

protected void initCustomTypeMappings(Collection<ExtendedScalarTypeDefinition> scalarTypeDefinitions) {
for (ExtendedScalarTypeDefinition definition : scalarTypeDefinitions) {
if (definition.getDefinition() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.kobylynskyi.graphql.codegen.model.MultiLanguageDeprecated;
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import graphql.language.Argument;
import graphql.language.Directive;
Expand Down Expand Up @@ -262,18 +263,18 @@ default List<String> getAnnotations(MappingContext mappingContext, Type<?> type,
return getAnnotations(mappingContext, ((NonNullType) type).getType(), def, parentTypeName, true);
} else if (type instanceof TypeName) {
return getAnnotations(mappingContext, ((TypeName) type).getName(), def.getName(), parentTypeName,
getDirectives(def), mandatory);
getDirectives(def), mandatory, false);
}
return Collections.emptyList();
}

default List<String> getAnnotations(MappingContext mappingContext, ExtendedDefinition<?, ?> extendedDefinition) {
return getAnnotations(mappingContext, extendedDefinition.getName(), extendedDefinition.getName(), null,
Collections.emptyList(), false);
Collections.emptyList(), false, extendedDefinition instanceof ExtendedUnionTypeDefinition);
}

default List<String> getAnnotations(MappingContext mappingContext, String name) {
return getAnnotations(mappingContext, name, name, null, Collections.emptyList(), false);
return getAnnotations(mappingContext, name, name, null, Collections.emptyList(), false, false);
}

/**
Expand All @@ -288,7 +289,8 @@ default List<String> getAnnotations(MappingContext mappingContext, String name)
* @return list of Java annotations for a given GraphQL type
*/
default List<String> getAnnotations(MappingContext mappingContext, String graphQLTypeName, String name,
String parentTypeName, List<Directive> directives, boolean mandatory) {
String parentTypeName, List<Directive> directives, boolean mandatory,
boolean isUnion) {
List<String> annotations = new ArrayList<>();
if (mandatory) {
String possiblyPrimitiveType = mappingContext.getCustomTypesMapping()
Expand All @@ -312,6 +314,17 @@ default List<String> getAnnotations(MappingContext mappingContext, String graphQ
if (!Utils.isEmpty(annotationsToAdd)) {
annotations.addAll(annotationsToAdd);
}
} else if (Boolean.TRUE.equals(mappingContext.getGenerateJacksonTypeIdResolver()) && isUnion) {
annotations.add("com.fasterxml.jackson.annotation.JsonTypeInfo(use = " +
"com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME, property = \"__typename\")");
String modelPackageName = DataModelMapper.getModelPackageName(mappingContext);
if (modelPackageName == null) {
modelPackageName = "";
} else if (Utils.isNotBlank(modelPackageName)) {
modelPackageName += ".";
}
annotations.add("com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver(" + modelPackageName +
"GraphqlJacksonTypeIdResolver.class)");
}

Map<String, List<String>> directiveAnnotationsMapping = mappingContext.getDirectiveAnnotationsMapping();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public final class DataModelFields {
public static final String PACKAGE = "package";
public static final String IMPORTS = "imports";
public static final String CLASS_NAME = "className";
public static final String MODEL_NAME_PREFIX = "modelNamePrefix";
public static final String MODEL_NAME_SUFFIX = "modelNameSuffix";
public static final String NAME = "name";
public static final String FIELDS = "fields";
public static final String IMPLEMENTS = "implements";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,15 @@ public interface GraphQLCodegenConfiguration {
*/
Boolean getAddGeneratedAnnotation();

/**
* Specifies whether generated union interfaces should be annotated with a Jackson type id resolver generated in
* model package.
*
* @return <b>true</b> if union interfaces should be annotated with a Jackson type id resolver generated in model
* package
*/
Boolean getGenerateJacksonTypeIdResolver();

/**
* Relay-related configurations.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
private Boolean useOptionalForNullableReturnTypes;
private Boolean generateApisWithThrowsException;
private Boolean addGeneratedAnnotation;
private Boolean generateJacksonTypeIdResolver;

// field resolvers configs:
private Set<String> fieldsWithResolvers = new HashSet<>();
Expand Down Expand Up @@ -150,6 +151,8 @@ public void combine(MappingConfig source) {
GraphQLCodegenConfiguration::getGenerateApisWithThrowsException);
addGeneratedAnnotation = getValueOrDefaultToThis(source,
GraphQLCodegenConfiguration::getAddGeneratedAnnotation);
generateJacksonTypeIdResolver = getValueOrDefaultToThis(source,
GraphQLCodegenConfiguration::getGenerateJacksonTypeIdResolver);
relayConfig = getValueOrDefaultToThis(source, GraphQLCodegenConfiguration::getRelayConfig);
queryResolverParentInterface = getValueOrDefaultToThis(source,
GraphQLCodegenConfiguration::getQueryResolverParentInterface);
Expand Down Expand Up @@ -461,6 +464,15 @@ public void setAddGeneratedAnnotation(Boolean addGeneratedAnnotation) {
this.addGeneratedAnnotation = addGeneratedAnnotation;
}

@Override
public Boolean getGenerateJacksonTypeIdResolver() {
return generateJacksonTypeIdResolver;
}

public void setGenerateJacksonTypeIdResolver(Boolean generateJacksonTypeIdResolver) {
this.generateJacksonTypeIdResolver = generateJacksonTypeIdResolver;
}

@Override
public RelayConfig getRelayConfig() {
return relayConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class MappingConfigConstants {
public static final String DEFAULT_GENERATE_APIS_WITH_THROWS_EXCEPTION_STRING = "true";
public static final boolean DEFAULT_ADD_GENERATED_ANNOTATION = true;
public static final String DEFAULT_ADD_GENERATED_ANNOTATION_STRING = "true";
public static final boolean DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER = false;
public static final String DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER_STRING = "false";
public static final boolean DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES = false;
public static final String DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES_STRING = "false";
public static final ApiNamePrefixStrategy DEFAULT_API_NAME_PREFIX_STRATEGY = ApiNamePrefixStrategy.CONSTANT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ public Boolean getAddGeneratedAnnotation() {
return config.getAddGeneratedAnnotation();
}

@Override
public Boolean getGenerateJacksonTypeIdResolver() {
return config.getGenerateJacksonTypeIdResolver();
}

@Override
public RelayConfig getRelayConfig() {
return config.getRelayConfig();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<#if package?has_content>
package ${package};

</#if>
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;

<#if generatedAnnotation && generatedInfo.getGeneratedType()?has_content>
@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
)
</#if>
public class GraphqlJacksonTypeIdResolver extends TypeIdResolverBase {

private JavaType superType;

@Override
public void init(JavaType baseType) {
superType = baseType;
}

@Override
public JavaType typeFromId(DatabindContext context, String typename) {
try {
var clazz = Class.forName(
<#if package?has_content>"${package}." +
</#if><#if modelNamePrefix?has_content>"${modelNamePrefix}" +
</#if>typename<#if modelNamePrefix?has_content> +
"${modelNameSuffix}"</#if>
);
return context.constructSpecializedType(superType, clazz);
} catch (ClassNotFoundException e) {
System.err.println(e.getMessage());
return null;
}
}

@Override
public JsonTypeInfo.Id getMechanism() {
return JsonTypeInfo.Id.NAME;
}

@Override
public String idFromValue(Object obj) {
return idFromValueAndType(obj, obj.getClass());
}

@Override
public String idFromValueAndType(Object obj, Class<?> subType) {
return subType.getSimpleName();
}
}
Loading