springfox.documentation.schema.property.field.FieldModelPropertyProvider.java Source code

Java tutorial

Introduction

Here is the source code for springfox.documentation.schema.property.field.FieldModelPropertyProvider.java

Source

/*
 *
 *  Copyright 2015 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package springfox.documentation.schema.property.field;

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import com.fasterxml.classmate.members.ResolvedField;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.schema.Annotations;
import springfox.documentation.schema.ModelProperty;
import springfox.documentation.schema.TypeNameExtractor;
import springfox.documentation.schema.configuration.ObjectMapperConfigured;
import springfox.documentation.schema.plugins.SchemaPluginsManager;
import springfox.documentation.schema.property.BeanPropertyDefinitions;
import springfox.documentation.schema.property.BeanPropertyNamingStrategy;
import springfox.documentation.schema.property.provider.ModelPropertiesProvider;
import springfox.documentation.spi.schema.contexts.ModelContext;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import static com.google.common.collect.Lists.*;
import static springfox.documentation.schema.ResolvedTypes.*;

@Component
public class FieldModelPropertyProvider implements ModelPropertiesProvider {

    private final FieldProvider fieldProvider;
    private final BeanPropertyNamingStrategy namingStrategy;
    private final SchemaPluginsManager schemaPluginsManager;
    private final TypeNameExtractor typeNameExtractor;
    protected ObjectMapper objectMapper;

    @Autowired
    public FieldModelPropertyProvider(FieldProvider fieldProvider, BeanPropertyNamingStrategy namingStrategy,
            SchemaPluginsManager schemaPluginsManager, TypeNameExtractor typeNameExtractor) {

        this.fieldProvider = fieldProvider;
        this.namingStrategy = namingStrategy;
        this.schemaPluginsManager = schemaPluginsManager;
        this.typeNameExtractor = typeNameExtractor;
    }

    @VisibleForTesting
    List<ModelProperty> addSerializationCandidates(AnnotatedMember member, ResolvedField childField,
            Optional<BeanPropertyDefinition> jacksonProperty, ModelContext givenContext) {
        if (memberIsAField(member)) {
            if (Annotations.memberIsUnwrapped(member)) {
                return propertiesFor(childField.getType(),
                        ModelContext.fromParent(givenContext, childField.getType()));
            } else {
                String fieldName = BeanPropertyDefinitions.name(jacksonProperty.get(), true, namingStrategy);
                return newArrayList(modelPropertyFrom(childField, fieldName, givenContext));
            }
        }
        return newArrayList();
    }

    private ModelProperty modelPropertyFrom(ResolvedField childField, String fieldName, ModelContext modelContext) {
        FieldModelProperty fieldModelProperty = new FieldModelProperty(fieldName, childField,
                modelContext.getAlternateTypeProvider());
        ModelPropertyBuilder propertyBuilder = new ModelPropertyBuilder().name(fieldModelProperty.getName())
                .type(fieldModelProperty.getType()).qualifiedType(fieldModelProperty.qualifiedTypeName())
                .position(fieldModelProperty.position()).required(fieldModelProperty.isRequired())
                .description(fieldModelProperty.propertyDescription())
                .allowableValues(fieldModelProperty.allowableValues());
        return schemaPluginsManager
                .property(new ModelPropertyContext(propertyBuilder, childField.getRawMember(), new TypeResolver(),
                        modelContext.getDocumentationType()))
                .updateModelRef(modelRefFactory(modelContext, typeNameExtractor));
    }

    @Override
    public List<ModelProperty> propertiesFor(ResolvedType type, ModelContext givenContext) {

        List<ModelProperty> serializationCandidates = newArrayList();
        BeanDescription beanDescription = beanDescription(type, givenContext);
        Map<String, BeanPropertyDefinition> propertyLookup = Maps.uniqueIndex(beanDescription.findProperties(),
                BeanPropertyDefinitions.beanPropertyByInternalName());

        for (ResolvedField childField : fieldProvider.in(type)) {
            if (propertyLookup.containsKey(childField.getName())) {
                BeanPropertyDefinition propertyDefinition = propertyLookup.get(childField.getName());
                Optional<BeanPropertyDefinition> jacksonProperty = BeanPropertyDefinitions
                        .jacksonPropertyWithSameInternalName(beanDescription, propertyDefinition);
                AnnotatedMember member = propertyDefinition.getPrimaryMember();
                serializationCandidates.addAll(newArrayList(
                        addSerializationCandidates(member, childField, jacksonProperty, givenContext)));
            }
        }
        return serializationCandidates;
    }

    private BeanDescription beanDescription(ResolvedType type, ModelContext context) {
        if (context.isReturnType()) {
            SerializationConfig serializationConfig = objectMapper.getSerializationConfig();
            return serializationConfig
                    .introspect(TypeFactory.defaultInstance().constructType(type.getErasedType()));
        } else {
            DeserializationConfig serializationConfig = objectMapper.getDeserializationConfig();
            return serializationConfig
                    .introspect(TypeFactory.defaultInstance().constructType(type.getErasedType()));
        }
    }

    public void onApplicationEvent(ObjectMapperConfigured event) {
        this.objectMapper = event.getObjectMapper();
    }

    protected boolean memberIsAField(AnnotatedMember member) {
        return member != null && member.getMember() != null
                && Field.class.isAssignableFrom(member.getMember().getClass());
    }
}