Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ trait GraphQLCodegenKeys {

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

val generateJacksonTypeIdResolver = settingKey[Boolean]("Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package")

//for version
val javaxValidationApiVersion = settingKey[Option[String]]("javax-validation-api version")
val graphqlJavaCodegenVersion = settingKey[Option[String]]("graphql java codegen version")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
configurationFiles := Seq.empty[String],
graphqlSchemaPaths := Seq.empty,
graphqlSchemaValidate := Seq.empty,
generateJacksonTypeIdResolver := MappingConfigConstants.DEFAULT_GENERATE_JACKSON_TYPE_ID_RESOLVER,
customTypesMapping := new JHashMap[String, String](), //TODO use scala Map, convert to java Map
customAnnotationsMapping := new JHashMap[String, JList[String]](),
directiveAnnotationsMapping := new JHashMap[String, JList[String]](),
Expand Down Expand Up @@ -167,6 +168,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
mappingConfig.setRelayConfig((relayConfig in GraphQLCodegenConfig).value)
mappingConfig.setGeneratedLanguage((generatedLanguage in GraphQLCodegenConfig).value)
mappingConfig.setGenerateModelOpenClasses((generateModelOpenClasses in GraphQLCodegenConfig).value)
mappingConfig.setGenerateJacksonTypeIdResolver((generateJacksonTypeIdResolver in GraphQLCodegenConfig).value);
mappingConfig
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class FreeMarkerTemplatesRegistry {
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlParametrizedInput.ftl"));
scalaTemplates.put(RESPONSE_PROJECTION,
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlResponseProjection.ftl"));
scalaTemplates.put(JACKSON_TYPE_ID_RESOLVER,
configuration.getTemplate("templates/scala-lang/scalaClassGraphqlJacksonTypeIdResolver.ftl"));
templateMap.put(GeneratedLanguage.SCALA, scalaTemplates);

EnumMap<FreeMarkerTemplateType, Template> kotlinTemplates = new EnumMap<>(FreeMarkerTemplateType.class);
Expand All @@ -103,6 +105,8 @@ class FreeMarkerTemplatesRegistry {
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlParametrizedInput.ftl"));
kotlinTemplates.put(RESPONSE_PROJECTION,
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlResponseProjection.ftl"));
kotlinTemplates.put(JACKSON_TYPE_ID_RESOLVER,
configuration.getTemplate("templates/kotlin-lang/kotlinClassGraphqlJacksonTypeIdResolver.ftl"));
templateMap.put(GeneratedLanguage.KOTLIN, kotlinTemplates);
} catch (IOException e) {
throw new UnableToLoadFreeMarkerTemplateException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -122,4 +124,22 @@ public ValueMapper getValueMapper() {
return valueMapper;
}

@Override
public List<String> getJacksonTypeIdAnnotations(MappingContext mappingContext, boolean isUnion) {
List<String> defaults = new ArrayList<>();
if (Boolean.TRUE.equals(mappingContext.getGenerateJacksonTypeIdResolver()) && isUnion) {
defaults.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 += ".";
}
defaults.add("com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver(" + modelPackageName +
"GraphqlJacksonTypeIdResolver.class)");
}
return defaults;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static java.util.Arrays.asList;
Expand Down Expand Up @@ -173,4 +175,22 @@ public String getResponseReturnType(MappingContext mappingContext, NamedDefiniti
// Should fix it when generate response class.
return getTypeConsideringPrimitive(mappingContext, namedDefinition, computedTypeName);
}

@Override
public List<String> getJacksonTypeIdAnnotations(MappingContext mappingContext, boolean isUnion) {
List<String> defaults = new ArrayList<>();
if (Boolean.TRUE.equals(mappingContext.getGenerateJacksonTypeIdResolver()) && isUnion) {
defaults.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 += ".";
}
defaults.add("com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver(" + modelPackageName +
"GraphqlJacksonTypeIdResolver::class)");
}
return defaults;
}
}
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.ExtendedFieldDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import graphql.language.Argument;
Expand Down Expand Up @@ -262,19 +263,31 @@ default List<String> getAnnotations(MappingContext mappingContext, Type<?> type,
} else if (type instanceof NonNullType) {
return getAnnotations(mappingContext, ((NonNullType) type).getType(), def, parentTypeName, true);
} else if (type instanceof TypeName) {
String typeName = null;
if (def instanceof ExtendedFieldDefinition) {
typeName = ((TypeName) type).getName();
}
return getAnnotations(mappingContext, ((TypeName) type).getName(), def.getName(), parentTypeName,
getDirectives(def), mandatory, false);
getDirectives(def), mandatory, false, typeName);
}
return Collections.emptyList();
}

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

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

default List<String> getJacksonTypeIdAnnotations(MappingContext mappingContext, boolean isUnion) {
return new ArrayList<>();
}

default List<String> getAdditionalAnnotations(MappingContext mappingContext, String typeName) {
return new ArrayList<>();
}

/**
Expand All @@ -286,11 +299,13 @@ default List<String> getAnnotations(MappingContext mappingContext, String name)
* @param parentTypeName Name of the parent type
* @param directives List of GraphQL directive
* @param mandatory Type is mandatory
* @param isUnion Is it union type
* @param typeName Name of GraphQL type, but only not null when type is Enum
* @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,
boolean isUnion) {
boolean isUnion, String typeName) {
List<String> annotations = new ArrayList<>();
if (mandatory) {
String possiblyPrimitiveType = mappingContext.getCustomTypesMapping()
Expand All @@ -314,19 +329,11 @@ 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)");
}

annotations.addAll(getJacksonTypeIdAnnotations(mappingContext, isUnion));
annotations.addAll(getAdditionalAnnotations(mappingContext, typeName));

Map<String, List<String>> directiveAnnotationsMapping = mappingContext.getDirectiveAnnotationsMapping();
for (Directive directive : directives) {
if (directiveAnnotationsMapping.containsKey(directive.getName())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.kobylynskyi.graphql.codegen.scala;

import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.GraphQLTypeMapper;
import com.kobylynskyi.graphql.codegen.mapper.ValueMapper;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.kobylynskyi.graphql.codegen.java.JavaGraphQLTypeMapper.JAVA_UTIL_LIST;
Expand Down Expand Up @@ -112,4 +115,46 @@ public ValueMapper getValueMapper() {
return valueMapper;
}

@Override
public List<String> getJacksonTypeIdAnnotations(MappingContext mappingContext, boolean isUnion) {
List<String> defaults = new ArrayList<>();
if (Boolean.TRUE.equals(mappingContext.getGenerateJacksonTypeIdResolver()) && isUnion) {
defaults.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 += ".";
}
defaults.add("com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver(classOf[" + modelPackageName +
"GraphqlJacksonTypeIdResolver])");
}
return defaults;
}

@Override
public List<String> getAdditionalAnnotations(MappingContext mappingContext, String typeName) {
List<String> defaults = new ArrayList<>();
String typeNameWithPrefixAndSuffix = (mappingContext.getModelNamePrefix() == null ? ""
: mappingContext.getModelNamePrefix())
+ typeName
+ (mappingContext.getModelNameSuffix() == null ? "" : mappingContext.getModelNameSuffix());
boolean exists = null != mappingContext.getEnumImportItSelfInScala()
&& mappingContext.getEnumImportItSelfInScala()
.contains(typeNameWithPrefixAndSuffix);
// todo use switch
// Inspired by the pr https://github.com/kobylynskyi/graphql-java-codegen/pull/637/files
if (exists) {
String modelPackageName = DataModelMapper.getModelPackageName(mappingContext);
if (modelPackageName == null) {
modelPackageName = "";
} else if (Utils.isNotBlank(modelPackageName)) {
modelPackageName += ".";
}
defaults.add("com.fasterxml.jackson.module.scala.JsonScalaEnumeration(classOf[" + modelPackageName
+ typeNameWithPrefixAndSuffix + "TypeRefer])");
}
return defaults;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class GraphqlJacksonTypeIdResolver extends TypeIdResolverBase {
@Override
public JavaType typeFromId(DatabindContext context, String typename) {
try {
var clazz = Class.forName(
Class<?> clazz = Class.forName(
<#if package?has_content>"${package}." +
</#if><#if modelNamePrefix?has_content>"${modelNamePrefix}" +
</#if>typename<#if modelNamePrefix?has_content> +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<#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>
open class GraphqlJacksonTypeIdResolver : TypeIdResolverBase() {

private var superType: JavaType? = null

override fun init(baseType: JavaType?) {
superType = baseType
}

override fun typeFromId(context: DatabindContext, typename: String): JavaType? {
return try {
val clazz = Class.forName(<#if package?has_content>"${package}." +
</#if><#if modelNamePrefix?has_content>"${modelNamePrefix}" +
</#if>typename<#if modelNamePrefix?has_content> +
"${modelNameSuffix}"</#if>)
context.constructSpecializedType(superType, clazz)
} catch (e: ClassNotFoundException) {
System.err.println(e.message)
null
}
}

override fun getMechanism(): JsonTypeInfo.Id {
return JsonTypeInfo.Id.NAME
}

override fun idFromValue(obj: Any): String {
return idFromValueAndType(obj, obj.javaClass)
}

override fun idFromValueAndType(obj: Any, subType: Class<*>): String {
return subType.simpleName
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<#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 = Array("com.kobylynskyi.graphql.codegen.GraphQLCodegen"),
date = "${generatedInfo.getDateTime()}"
)
</#if>
class GraphqlJacksonTypeIdResolver extends TypeIdResolverBase {

private var superType: JavaType = _

override def init(baseType: JavaType): Unit = {
superType = baseType
}

override def typeFromId(context: DatabindContext, typename: String): JavaType = try {
val clazz = Class.forName(<#if package?has_content>"${package}." +
</#if><#if modelNamePrefix?has_content>"${modelNamePrefix}" +
</#if>typename<#if modelNamePrefix?has_content> +
"${modelNameSuffix}"</#if>)
context.constructSpecializedType(superType, clazz)
} catch {
case e: ClassNotFoundException =>
Console.err.println(e.getMessage)
null
}

override def getMechanism = JsonTypeInfo.Id.NAME

override def idFromValue(obj: Any): String = idFromValueAndType(obj, obj.getClass)

override def idFromValueAndType(obj: Any, subType: Class[_]): String = subType.getSimpleName
}
Loading