TypeDefinitionToDataModelMapper.java 8.3 KB
Newer Older
1 2
package com.kobylynskyi.graphql.codegen.mapper;

3
import com.kobylynskyi.graphql.codegen.model.MappingContext;
4
import com.kobylynskyi.graphql.codegen.model.ParameterDefinition;
5
import com.kobylynskyi.graphql.codegen.model.builders.JavaDocBuilder;
6 7 8
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDocument;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedObjectTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
9
import com.kobylynskyi.graphql.codegen.utils.Utils;
10

11 12 13 14 15 16 17
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
18 19
import java.util.stream.Collectors;

20
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.ANNOTATIONS;
21
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.INITIALIZE_NULLABLE_TYPES;
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
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;
37 38 39 40 41 42 43 44

/**
 * Map type definition to a Freemarker data model
 *
 * @author kobylynskyi
 */
public class TypeDefinitionToDataModelMapper {

45
    private final GraphQLTypeMapper graphQLTypeMapper;
46
    private final AnnotationsMapper annotationsMapper;
47 48 49
    private final DataModelMapper dataModelMapper;
    private final FieldDefinitionToParameterMapper fieldDefinitionToParameterMapper;

50
    public TypeDefinitionToDataModelMapper(MapperFactory mapperFactory,
51
                                           FieldDefinitionToParameterMapper fieldDefinitionToParameterMapper) {
52 53 54
        this.graphQLTypeMapper = mapperFactory.getGraphQLTypeMapper();
        this.annotationsMapper = mapperFactory.getAnnotationsMapper();
        this.dataModelMapper = mapperFactory.getDataModelMapper();
55 56 57 58 59 60 61 62 63 64 65 66
        this.fieldDefinitionToParameterMapper = fieldDefinitionToParameterMapper;
    }

    /**
     * Merge parameter definition data from the type and interface
     * Annotations from the type have higher precedence
     *
     * @param typeDef      Definition of the same parameter from the type
     * @param interfaceDef Definition of the same parameter from the interface
     * @return merged parameter definition
     */
    private static ParameterDefinition merge(ParameterDefinition typeDef, ParameterDefinition interfaceDef) {
67
        typeDef.setDefinitionInParentType(interfaceDef);
68 69 70 71 72 73 74
        if (Utils.isEmpty(typeDef.getAnnotations())) {
            typeDef.setAnnotations(interfaceDef.getAnnotations());
        }
        if (Utils.isEmpty(typeDef.getJavaDoc())) {
            typeDef.setJavaDoc(interfaceDef.getJavaDoc());
        }
        return typeDef;
B
Bogdan Kobylynskyi 已提交
75 76
    }

77 78 79
    /**
     * Map type definition to a Freemarker data model
     *
80 81
     * @param mappingContext Global mapping context
     * @param definition     Definition of object type including base definition and its extensions
82 83
     * @return Freemarker data model of the GraphQL type
     */
84 85
    public Map<String, Object> map(MappingContext mappingContext,
                                   ExtendedObjectTypeDefinition definition) {
86 87
        ExtendedDocument document = mappingContext.getDocument();

88
        Map<String, Object> dataModel = new HashMap<>();
89
        // type/enum/input/interface/union classes do not require any imports
90 91
        dataModel.put(PACKAGE, DataModelMapper.getModelPackageName(mappingContext));
        dataModel.put(CLASS_NAME, dataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, definition));
92
        dataModel.put(JAVA_DOC, JavaDocBuilder.build(definition));
93
        dataModel.put(IMPLEMENTS, getInterfaces(mappingContext, definition));
94
        dataModel.put(ANNOTATIONS, annotationsMapper.getAnnotations(mappingContext, definition));
95 96 97
        dataModel.put(FIELDS, getFields(mappingContext, definition, document));
        dataModel.put(BUILDER, mappingContext.getGenerateBuilder());
        dataModel.put(EQUALS_AND_HASH_CODE, mappingContext.getGenerateEqualsAndHashCode());
98
        dataModel.put(IMMUTABLE_MODELS, mappingContext.getGenerateImmutableModels());
99
        dataModel.put(TO_STRING, mappingContext.getGenerateToString());
100
        dataModel.put(TO_STRING_FOR_REQUEST, mappingContext.getGenerateClient());
101
        dataModel.put(GENERATED_ANNOTATION, mappingContext.getAddGeneratedAnnotation());
102
        dataModel.put(GENERATED_INFO, mappingContext.getGeneratedInformation());
103
        dataModel.put(ENUM_IMPORT_IT_SELF_IN_SCALA, mappingContext.getEnumImportItSelfInScala());
梦境迷离's avatar
梦境迷离 已提交
104
        dataModel.put(PARENT_INTERFACE_PROPERTIES, mappingContext.getParentInterfaceProperties());
105
        dataModel.put(GENERATE_MODEL_OPEN_CLASSES, mappingContext.isGenerateModelOpenClasses());
106
        dataModel.put(INITIALIZE_NULLABLE_TYPES, mappingContext.isInitializeNullableTypes());
107 108 109
        return dataModel;
    }

110 111 112
    /**
     * Get merged attributes from the type and attributes from the interface.
     *
113
     * @param mappingContext Global mapping context
114 115 116 117
     * @param typeDefinition GraphQL type definition
     * @param document       Parent GraphQL document
     * @return Freemarker data model of the GraphQL type
     */
118 119 120
    private Collection<ParameterDefinition> getFields(MappingContext mappingContext,
                                                      ExtendedObjectTypeDefinition typeDefinition,
                                                      ExtendedDocument document) {
121 122 123 124
        // using the map to exclude duplicate fields from the type and interfaces
        Map<String, ParameterDefinition> allParameters = new LinkedHashMap<>();

        // includes parameters from the base definition and extensions
125
        fieldDefinitionToParameterMapper.mapFields(mappingContext, typeDefinition.getFieldDefinitions(), typeDefinition)
126 127
                .forEach(p -> allParameters.put(p.getName(), p));
        // includes parameters from the interface
128 129
        DataModelMapper.getInterfacesOfType(typeDefinition, document).stream()
                .map(i -> fieldDefinitionToParameterMapper.mapFields(mappingContext, i.getFieldDefinitions(), i))
130
                .flatMap(Collection::stream)
131 132
                .forEach(paramDef -> allParameters
                        .merge(paramDef.getName(), paramDef, TypeDefinitionToDataModelMapper::merge));
133 134
        return allParameters.values();
    }
135

136 137
    private Set<String> getInterfaces(MappingContext mappingContext,
                                      ExtendedObjectTypeDefinition definition) {
138
        List<String> unionsNames = mappingContext.getDocument().getUnionDefinitions()
139 140 141
                .stream()
                .filter(union -> union.isDefinitionPartOfUnion(definition))
                .map(ExtendedUnionTypeDefinition::getName)
142 143
                .map(unionName -> DataModelMapper
                        .getModelClassNameWithPrefixAndSuffix(mappingContext, unionName))
144 145 146
                .collect(Collectors.toList());
        Set<String> interfaceNames = definition.getImplements()
                .stream()
147
                .map(anImplement -> graphQLTypeMapper.getLanguageType(mappingContext, anImplement))
148 149 150 151 152
                .collect(Collectors.toSet());

        Set<String> allInterfaces = new LinkedHashSet<>();
        allInterfaces.addAll(unionsNames);
        allInterfaces.addAll(interfaceNames);
153 154 155
        return allInterfaces;
    }

156
}