Java tutorial
/* * * 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.swagger2.mappers; import com.fasterxml.classmate.ResolvedType; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.Multimap; import io.swagger.models.Model; import io.swagger.models.ModelImpl; import io.swagger.models.properties.AbstractNumericProperty; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.ObjectProperty; import io.swagger.models.properties.Property; import io.swagger.models.properties.StringProperty; import org.mapstruct.Mapper; import springfox.documentation.schema.ModelProperty; import springfox.documentation.schema.ModelReference; import springfox.documentation.service.AllowableRangeValues; import springfox.documentation.service.AllowableValues; import springfox.documentation.service.ApiListing; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import static com.google.common.base.Predicates.*; import static com.google.common.collect.Maps.*; import static springfox.documentation.schema.Maps.*; import static springfox.documentation.swagger2.mappers.EnumMapper.*; import static springfox.documentation.swagger2.mappers.Properties.*; @Mapper public abstract class ModelMapper { public Map<String, Model> mapModels(Map<String, springfox.documentation.schema.Model> from) { if (from == null) { return null; } Map<String, Model> map = new HashMap<String, Model>(); for (java.util.Map.Entry<String, springfox.documentation.schema.Model> entry : from.entrySet()) { String key = entry.getKey(); Model value = mapProperties(entry.getValue()); map.put(key, value); } return map; } private Model mapProperties(springfox.documentation.schema.Model source) { ModelImpl model = new ModelImpl().description(source.getDescription()) .discriminator(source.getDiscriminator()).example(source.getExample()).name(source.getName()); SortedMap<String, ModelProperty> sortedProperties = sort(source.getProperties()); Map<String, Property> modelProperties = mapProperties(sortedProperties); model.setProperties(modelProperties); FluentIterable<String> requiredFields = FluentIterable.from(source.getProperties().values()) .filter(requiredProperty()).transform(propertyName()); model.setRequired(requiredFields.toList()); model.setSimple(false); model.setType(ModelImpl.OBJECT); if (isMapType(source.getType())) { Optional<Class> clazz = typeOfValue(source); if (clazz.isPresent()) { model.additionalProperties(property(clazz.get().getSimpleName())); } else { model.additionalProperties(new ObjectProperty()); } } return model; } private Map<String, Property> mapProperties(SortedMap<String, ModelProperty> properties) { Map<String, Property> mappedProperties = new LinkedHashMap<String, Property>(); SortedMap<String, ModelProperty> nonVoidProperties = filterEntries(properties, not(voidProperties())); for (Map.Entry<String, ModelProperty> propertyEntry : nonVoidProperties.entrySet()) { mappedProperties.put(propertyEntry.getKey(), mapProperty(propertyEntry.getValue())); } return mappedProperties; } /** * Returns a {@link TreeMap} where the keys are sorted by their respective property position values in ascending * order. * * @param modelProperties * @return */ private SortedMap<String, ModelProperty> sort(Map<String, ModelProperty> modelProperties) { SortedMap<String, ModelProperty> sortedMap = new TreeMap<String, ModelProperty>( defaultOrdering(modelProperties)); sortedMap.putAll(modelProperties); return sortedMap; } @VisibleForTesting Optional<Class> typeOfValue(springfox.documentation.schema.Model source) { Optional<ResolvedType> mapInterface = findMapInterface(source.getType()); if (mapInterface.isPresent()) { if (mapInterface.get().getTypeParameters().size() > 0) { return Optional.of((Class) mapInterface.get().getTypeParameters().get(1).getErasedType()); } return Optional.of((Class) Object.class); } return Optional.absent(); } private Optional<ResolvedType> findMapInterface(ResolvedType type) { return Optional.fromNullable(type.findSupertype(Map.class)); } private Property mapProperty(ModelProperty source) { Property property = modelRefToProperty(source.getModelRef()); maybeAddAllowableValues(property, source.getAllowableValues()); if (property instanceof ArrayProperty) { ArrayProperty arrayProperty = (ArrayProperty) property; maybeAddAllowableValues(arrayProperty.getItems(), source.getAllowableValues()); } if (property instanceof AbstractNumericProperty) { AbstractNumericProperty numericProperty = (AbstractNumericProperty) property; AllowableValues allowableValues = source.getAllowableValues(); if (allowableValues instanceof AllowableRangeValues) { AllowableRangeValues range = (AllowableRangeValues) allowableValues; numericProperty.maximum(safeDouble(range.getMax())); numericProperty.exclusiveMaximum(range.getExclusiveMax()); numericProperty.minimum(safeDouble(range.getMin())); numericProperty.exclusiveMinimum(range.getExclusiveMin()); } } if (property instanceof StringProperty) { StringProperty stringProperty = (StringProperty) property; AllowableValues allowableValues = source.getAllowableValues(); if (allowableValues instanceof AllowableRangeValues) { AllowableRangeValues range = (AllowableRangeValues) allowableValues; stringProperty.maxLength(safeInteger(range.getMax())); stringProperty.minLength(safeInteger(range.getMin())); } if (source.getPattern() != null) { stringProperty.setPattern(source.getPattern()); } } if (property != null) { property.setDescription(source.getDescription()); property.setName(source.getName()); property.setRequired(source.isRequired()); property.setReadOnly(source.isReadOnly()); property.setExample(source.getExample()); } return property; } static Integer safeInteger(String doubleString) { try { return Integer.valueOf(doubleString); } catch (NumberFormatException e) { return null; } } static Property modelRefToProperty(ModelReference modelRef) { if (modelRef == null || "void".equalsIgnoreCase(modelRef.getType())) { return null; } Property responseProperty; if (modelRef.isCollection()) { responseProperty = new ArrayProperty(maybeAddAllowableValues( itemTypeProperty(modelRef.itemModel().get()), modelRef.getAllowableValues())); } else if (modelRef.isMap()) { responseProperty = new MapProperty(property(modelRef.itemModel().get())); } else { responseProperty = property(modelRef.getType()); } maybeAddAllowableValues(responseProperty, modelRef.getAllowableValues()); return responseProperty; } Map<String, Model> modelsFromApiListings(Multimap<String, ApiListing> apiListings) { Map<String, springfox.documentation.schema.Model> definitions = newHashMap(); for (ApiListing each : apiListings.values()) { definitions.putAll(each.getModels()); } return mapModels(definitions); } private Function<ModelProperty, String> propertyName() { return new Function<ModelProperty, String>() { @Override public String apply(ModelProperty input) { return input.getName(); } }; } private Predicate<ModelProperty> requiredProperty() { return new Predicate<ModelProperty>() { @Override public boolean apply(ModelProperty input) { return input.isRequired(); } }; } }