未验证 提交 c8df4854 编写于 作者: B Bogdan Kobylynskyi 提交者: GitHub

Fix a case when field is non-null in type and nullable in interface #556 (#557)

上级 8c46e67c
......@@ -121,6 +121,7 @@ public class FieldDefinitionToParameterMapper {
parameter.setAnnotations(graphQLTypeMapper.getAnnotations(mappingContext, fieldDef.getType(), fieldDef, parentTypeName, false));
parameter.setJavaDoc(fieldDef.getJavaDoc());
parameter.setDeprecated(fieldDef.getDeprecated(mappingContext));
parameter.setMandatory(namedDefinition.isMandatory());
parameter.setSerializeUsingObjectMapper(namedDefinition.isSerializeUsingObjectMapper());
return parameter;
}
......
......@@ -22,9 +22,17 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.*;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.CLASS_NAME;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.ENUM_IMPORT_IT_SELF_IN_SCALA;
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.GENERATE_MODEL_OPEN_CLASSES;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.IMPLEMENTS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.IMPORTS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.JAVA_DOC;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.OPERATIONS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.PACKAGE;
import static com.kobylynskyi.graphql.codegen.model.MappingConfigConstants.PARENT_INTERFACE_TYPE_PLACEHOLDER;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
/**
......@@ -197,7 +205,12 @@ public class FieldDefinitionsToResolverDataModelMapper {
if (!Utils.isGraphqlOperation(parentTypeName)) {
String parentObjectParamType = graphQLTypeMapper.getLanguageType(mappingContext, new TypeName(parentTypeName));
String parentObjectParamName = dataModelMapper.capitalizeIfRestricted(mappingContext, Utils.uncapitalize(parentObjectParamType));
parameters.add(new ParameterDefinition(parentObjectParamType, parentObjectParamName, parentObjectParamName, null, emptyList(), emptyList(), resolvedField.getDeprecated(mappingContext), false));
ParameterDefinition parameterDefinition = new ParameterDefinition();
parameterDefinition.setType(parentObjectParamType);
parameterDefinition.setName(parentObjectParamName);
parameterDefinition.setOriginalName(parentObjectParamName);
parameterDefinition.setDeprecated(resolvedField.getDeprecated(mappingContext));
parameters.add(parameterDefinition);
}
// 2. Next parameters are input values
......
......@@ -60,6 +60,7 @@ public class InputValueDefinitionToParameterMapper {
parameter.setDefaultValue(valueMapper.map(mappingContext, inputValueDefinition.getDefaultValue(), inputValueDefinition.getType()));
parameter.setAnnotations(graphQLTypeMapper.getAnnotations(mappingContext, inputValueDefinition.getType(), inputValueDefinition, parentTypeName, false));
parameter.setDeprecated(graphQLTypeMapper.getDeprecated(mappingContext, inputValueDefinition));
parameter.setMandatory(namedDefinition.isMandatory());
parameter.setSerializeUsingObjectMapper(namedDefinition.isSerializeUsingObjectMapper());
return parameter;
}
......
......@@ -16,7 +16,22 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.*;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.ANNOTATIONS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.BUILDER;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.CLASS_NAME;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.ENUM_IMPORT_IT_SELF_IN_SCALA;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.EQUALS_AND_HASH_CODE;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.FIELDS;
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.GENERATE_MODEL_OPEN_CLASSES;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.IMMUTABLE_MODELS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.IMPLEMENTS;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.JAVA_DOC;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.PACKAGE;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.PARENT_INTERFACE_PROPERTIES;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.TO_STRING;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.TO_STRING_FOR_REQUEST;
/**
* Map type definition to a Freemarker data model
......@@ -46,6 +61,7 @@ public class TypeDefinitionToDataModelMapper {
* @return merged parameter definition
*/
private static ParameterDefinition merge(ParameterDefinition typeDef, ParameterDefinition interfaceDef) {
typeDef.setDefinitionInParentType(interfaceDef);
if (Utils.isEmpty(typeDef.getAnnotations())) {
typeDef.setAnnotations(interfaceDef.getAnnotations());
}
......
......@@ -6,8 +6,6 @@ import graphql.schema.DataFetchingEnvironment;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.emptyList;
/**
* Freemarker-understandable format of method parameter and field definition
*
......@@ -16,7 +14,7 @@ import static java.util.Collections.emptyList;
public class ParameterDefinition {
public static final ParameterDefinition DATA_FETCHING_ENVIRONMENT = new ParameterDefinition(
DataFetchingEnvironment.class.getName(), "env", "env", null, emptyList(), emptyList(), null, false);
DataFetchingEnvironment.class.getName(), "env");
private String type;
/**
......@@ -28,25 +26,23 @@ public class ParameterDefinition {
*/
private String originalName;
private String defaultValue;
private boolean isMandatory;
private List<String> annotations = new ArrayList<>();
private List<String> javaDoc = new ArrayList<>();
private DeprecatedDefinition deprecated;
private boolean serializeUsingObjectMapper;
/**
* Definition of the same type, but defined in the parent
*/
private ParameterDefinition definitionInParentType;
public ParameterDefinition() {
}
public ParameterDefinition(String type, String name, String originalName, String defaultValue,
List<String> annotations, List<String> javaDoc,
DeprecatedDefinition deprecated, boolean serializeUsingObjectMapper) {
private ParameterDefinition(String type, String name) {
this.type = type;
this.name = name;
this.originalName = originalName;
this.defaultValue = defaultValue;
this.annotations = annotations;
this.javaDoc = javaDoc;
this.deprecated = deprecated;
this.serializeUsingObjectMapper = serializeUsingObjectMapper;
this.originalName = name;
}
public String getType() {
......@@ -81,6 +77,14 @@ public class ParameterDefinition {
this.defaultValue = defaultValue;
}
public boolean isMandatory() {
return isMandatory;
}
public void setMandatory(boolean mandatory) {
isMandatory = mandatory;
}
public List<String> getAnnotations() {
return annotations;
}
......@@ -113,4 +117,11 @@ public class ParameterDefinition {
this.serializeUsingObjectMapper = serializeUsingObjectMapper;
}
public void setDefinitionInParentType(ParameterDefinition definitionInParentType) {
this.definitionInParentType = definitionInParentType;
}
public ParameterDefinition getDefinitionInParentType() {
return definitionInParentType;
}
}
......@@ -4,9 +4,9 @@ package ${package};
</#if>
<#if imports??>
<#list imports as import>
<#list imports as import>
import ${import}.*;
</#list>
</#list>
</#if>
<#if toStringForRequest>
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLRequestSerializer;
......@@ -20,9 +20,9 @@ import java.util.StringJoiner;
<#if javaDoc?has_content>
/**
<#list javaDoc as javaDocLine>
<#list javaDoc as javaDocLine>
* ${javaDocLine}
</#list>
</#list>
*/
</#if>
<#if generatedAnnotation && generatedInfo.getGeneratedType()?has_content>
......@@ -37,15 +37,15 @@ import java.util.StringJoiner;
public class ${className} implements java.io.Serializable<#if implements?has_content><#list implements as interface>, ${interface}<#if interface_has_next></#if></#list></#if> {
<#if fields?has_content>
<#list fields as field>
<#if field.deprecated?has_content>
<#list fields as field>
<#if field.deprecated?has_content>
@${field.deprecated.annotation}
</#if>
<#list field.annotations as annotation>
</#if>
<#list field.annotations as annotation>
@${annotation}
</#list>
</#list>
private ${field.type} ${field.name}<#if field.defaultValue?has_content> = ${field.defaultValue}</#if>;
</#list>
</#list>
</#if>
public ${className}() {
......@@ -53,44 +53,44 @@ public class ${className} implements java.io.Serializable<#if implements?has_con
<#if fields?has_content>
public ${className}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>) {
<#list fields as field>
<#list fields as field>
this.${field.name} = ${field.name};
</#list>
</#list>
}
</#if>
<#if fields?has_content>
<#list fields as field>
<#if field.javaDoc?has_content>
<#list fields as field>
<#if field.javaDoc?has_content>
/**
<#list field.javaDoc as javaDocLine>
<#list field.javaDoc as javaDocLine>
* ${javaDocLine}
</#list>
</#list>
*/
</#if>
<#if field.deprecated?has_content>
</#if>
<#if field.deprecated?has_content>
@${field.deprecated.annotation}
</#if>
public ${field.type} get${field.name?cap_first}() {
</#if>
public <#if field.mandatory && field.definitionInParentType?has_content && !field.definitionInParentType.mandatory>${field.definitionInParentType.type}<#else>${field.type}</#if> get${field.name?cap_first}() {
return ${field.name};
}
<#if !immutableModels>
<#if field.javaDoc?has_content>
<#if !immutableModels>
<#if field.javaDoc?has_content>
/**
<#list field.javaDoc as javaDocLine>
<#list field.javaDoc as javaDocLine>
* ${javaDocLine}
</#list>
</#list>
*/
</#if>
<#if field.deprecated?has_content>
</#if>
<#if field.deprecated?has_content>
@${field.deprecated.annotation}
</#if>
</#if>
public void set${field.name?cap_first}(${field.type} ${field.name}) {
this.${field.name} = ${field.name};
}
</#if>
</#if>
</#list>
</#list>
</#if>
<#if equalsAndHashCode>
@Override
......@@ -102,21 +102,21 @@ public class ${className} implements java.io.Serializable<#if implements?has_con
return false;
}
final ${className} that = (${className}) obj;
<#if fields?has_content>
<#if fields?has_content>
return <#list fields as field>Objects.equals(${field.name}, that.${field.name})<#if field_has_next>
&& </#if></#list>;
<#else>
<#else>
return true;
</#if>
</#if>
}
@Override
public int hashCode() {
<#if fields?has_content>
<#if fields?has_content>
return Objects.hash(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
<#else>
<#else>
return 0;
</#if>
</#if>
}
</#if>
......@@ -124,29 +124,29 @@ public class ${className} implements java.io.Serializable<#if implements?has_con
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(", ", "{ ", " }");
<#if fields?has_content>
<#list fields as field>
<#if MapperUtil.isJavaPrimitive(field.type)>
<#if toStringForRequest>
<#if fields?has_content>
<#list fields as field>
<#if MapperUtil.isJavaPrimitive(field.type)>
<#if toStringForRequest>
joiner.add("${field.originalName}: " + GraphQLRequestSerializer.getEntry(${field.name}<#if field.serializeUsingObjectMapper>, true</#if>));
<#else>
<#else>
joiner.add("${field.originalName}: " + ${field.name});
</#if>
<#else>
</#if>
<#else>
if (${field.name} != null) {
<#if toStringForRequest>
<#if toStringForRequest>
joiner.add("${field.originalName}: " + GraphQLRequestSerializer.getEntry(${field.name}<#if field.serializeUsingObjectMapper>, true</#if>));
<#else>
<#if field.type == "String">
<#else>
<#if field.type == "String">
joiner.add("${field.originalName}: \"" + ${field.name} + "\"");
<#else>
<#else>
joiner.add("${field.originalName}: " + ${field.name});
</#if>
</#if>
</#if>
</#if>
}
</#if>
</#list>
</#if>
</#if>
</#list>
</#if>
return joiner.toString();
}
</#if>
......@@ -158,34 +158,34 @@ public class ${className} implements java.io.Serializable<#if implements?has_con
public static class Builder {
<#if fields?has_content>
<#list fields as field>
<#if fields?has_content>
<#list fields as field>
private ${field.type} ${field.name}<#if field.defaultValue?has_content> = ${field.defaultValue}</#if>;
</#list>
</#if>
</#list>
</#if>
public Builder() {
}
<#if fields?has_content>
<#list fields as field>
<#if field.javaDoc?has_content>
<#if fields?has_content>
<#list fields as field>
<#if field.javaDoc?has_content>
/**
<#list field.javaDoc as javaDocLine>
<#list field.javaDoc as javaDocLine>
* ${javaDocLine}
</#list>
</#list>
*/
</#if>
<#if field.deprecated?has_content>
</#if>
<#if field.deprecated?has_content>
@${field.deprecated.annotation}
</#if>
</#if>
public Builder set${field.name?cap_first}(${field.type} ${field.name}) {
this.${field.name} = ${field.name};
return this;
}
</#list>
</#if>
</#list>
</#if>
public ${className} build() {
return new ${className}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
......
......@@ -24,7 +24,6 @@ class GraphQLCodegenOptionalTest {
@BeforeEach
void before() {
schemaFinder.setIncludePattern("github.*\\.graphqls");
mappingConfig.setUseOptionalForNullableReturnTypes(true);
}
......@@ -35,6 +34,7 @@ class GraphQLCodegenOptionalTest {
@Test
void generate_Optional() throws Exception {
schemaFinder.setIncludePattern("github.*\\.graphqls");
new JavaGraphQLCodegen(schemaFinder.findSchemas(), outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo())
.generate();
......@@ -59,6 +59,7 @@ class GraphQLCodegenOptionalTest {
@Test
void generate_OptionalWithCustomApiReturnType() throws Exception {
schemaFinder.setIncludePattern("github.*\\.graphqls");
mappingConfig.setApiReturnType("reactor.core.publisher.Mono");
mappingConfig.setApiReturnListType("reactor.core.publisher.Flux");
......@@ -72,4 +73,25 @@ class GraphQLCodegenOptionalTest {
getFileByName(files, "NodeQueryResolver.java"));
}
/**
* @see <a href="https://github.com/kobylynskyi/graphql-java-codegen/issues/556">Related issue in GitHub</a>
*/
@Test
void generate_OptionalFieldInInterfaceAndMandatoryInType() throws Exception {
mappingConfig.setGenerateBuilder(true);
mappingConfig.setGenerateToString(true);
mappingConfig.setGenerateEqualsAndHashCode(true);
schemaFinder.setIncludePattern("optional-vs-mandatory-types.graphqls");
new JavaGraphQLCodegen(schemaFinder.findSchemas(), outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo())
.generate();
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
assertSameTrimmedContent(new File("src/test/resources/expected-classes/optional/InterfaceWithOptionalField.java.txt"),
getFileByName(files, "InterfaceWithOptionalField.java"));
assertSameTrimmedContent(new File("src/test/resources/expected-classes/optional/TypeWithMandatoryField.java.txt"),
getFileByName(files, "TypeWithMandatoryField.java"));
}
}
\ No newline at end of file
@javax.annotation.Generated(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "2020-12-31T23:59:59-0500"
)
public interface InterfaceWithOptionalField {
Integer getTest();
}
\ No newline at end of file
import java.util.Objects;
import java.util.StringJoiner;
@javax.annotation.Generated(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "2020-12-31T23:59:59-0500"
)
public class TypeWithMandatoryField implements java.io.Serializable, InterfaceWithOptionalField {
private int test;
public TypeWithMandatoryField() {
}
public TypeWithMandatoryField(int test) {
this.test = test;
}
public Integer getTest() {
return test;
}
public void setTest(int test) {
this.test = test;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final TypeWithMandatoryField that = (TypeWithMandatoryField) obj;
return Objects.equals(test, that.test);
}
@Override
public int hashCode() {
return Objects.hash(test);
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(", ", "{ ", " }");
joiner.add("test: " + test);
return joiner.toString();
}
public static TypeWithMandatoryField.Builder builder() {
return new TypeWithMandatoryField.Builder();
}
public static class Builder {
private int test;
public Builder() {
}
public Builder setTest(int test) {
this.test = test;
return this;
}
public TypeWithMandatoryField build() {
return new TypeWithMandatoryField(test);
}
}
}
\ No newline at end of file
type TypeWithMandatoryField implements InterfaceWithOptionalField {
test: Int!
}
interface InterfaceWithOptionalField {
test: Int
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册