io.swagger.jackson.AbstractModelConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swagger-all Show documentation
Show all versions of swagger-all Show documentation
swagger-all is a rebundled verison of Swagger as one OSGi bundle.
package io.swagger.jackson;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyName;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.converter.ModelConverter;
import io.swagger.converter.ModelConverterContext;
import io.swagger.models.Model;
import io.swagger.models.properties.Property;
import javax.xml.bind.annotation.XmlElement;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractModelConverter implements ModelConverter {
protected final ObjectMapper _mapper;
protected final AnnotationIntrospector _intr;
protected final TypeNameResolver _typeNameResolver = TypeNameResolver.std;
/**
* Minor optimization: no need to keep on resolving same types over and over
* again.
*/
protected Map _resolvedTypeNames = new ConcurrentHashMap();
protected AbstractModelConverter(ObjectMapper mapper) {
mapper.registerModule(
new SimpleModule("swagger", Version.unknownVersion()) {
@Override
public void setupModule(SetupContext context) {
context.insertAnnotationIntrospector(new SwaggerAnnotationIntrospector());
}
});
_mapper = mapper;
_intr = mapper.getSerializationConfig().getAnnotationIntrospector();
}
protected static Comparator getPropertyComparator() {
return new Comparator() {
@Override
public int compare(Property one, Property two) {
if (one.getPosition() == null && two.getPosition() == null) {
return 0;
}
if (one.getPosition() == null) {
return -1;
}
if (two.getPosition() == null) {
return 1;
}
return one.getPosition().compareTo(two.getPosition());
}
};
}
@Override
public Property resolveProperty(Type type,
ModelConverterContext context,
Annotation[] annotations,
Iterator chain) {
if (chain.hasNext()) {
return chain.next().resolveProperty(type, context, annotations, chain);
} else {
return null;
}
}
protected String _description(Annotated ann) {
// while name suggests it's only for properties, should work for any Annotated thing.
// also; with Swagger introspector's help, should get it from ApiModel/ApiModelProperty
return _intr.findPropertyDescription(ann);
}
protected String _typeName(JavaType type) {
return _typeName(type, null);
}
protected String _typeName(JavaType type, BeanDescription beanDesc) {
String name = _resolvedTypeNames.get(type);
if (name != null) {
return name;
}
name = _findTypeName(type, beanDesc);
_resolvedTypeNames.put(type, name);
return name;
}
protected String _findTypeName(JavaType type, BeanDescription beanDesc) {
// First, handle container types; they require recursion
if (type.isArrayType()) {
return "Array";
}
if (type.isMapLikeType()) {
return "Map";
}
if (type.isContainerType()) {
if (Set.class.isAssignableFrom(type.getRawClass())) {
return "Set";
}
return "List";
}
if (beanDesc == null) {
beanDesc = _mapper.getSerializationConfig().introspectClassAnnotations(type);
}
PropertyName rootName = _intr.findRootName(beanDesc.getClassInfo());
if (rootName != null && rootName.hasSimpleName()) {
return rootName.getSimpleName();
}
return _typeNameResolver.nameForType(type);
}
protected String _typeQName(JavaType type) {
return type.getRawClass().getName();
}
protected String _subTypeName(NamedType type) {
// !!! TODO: should this use 'name' instead?
return type.getType().getName();
}
protected String _findDefaultValue(Annotated a) {
XmlElement elem = a.getAnnotation(XmlElement.class);
if (elem != null) {
if (!elem.defaultValue().isEmpty() && !"\u0000".equals(elem.defaultValue())) {
return elem.defaultValue();
}
}
return null;
}
protected String _findExampleValue(Annotated a) {
ApiModelProperty prop = a.getAnnotation(ApiModelProperty.class);
if (prop != null) {
if (!prop.example().isEmpty()) {
return prop.example();
}
}
return null;
}
protected Boolean _findReadOnly(Annotated a) {
ApiModelProperty prop = a.getAnnotation(ApiModelProperty.class);
if (prop != null) {
return prop.readOnly();
}
return null;
}
protected boolean _isSetType(Class> cls) {
if (cls != null) {
if (java.util.Set.class.equals(cls)) {
return true;
} else {
for (Class> a : cls.getInterfaces()) {
// this is dirty and ugly and needs to be extended into a scala model converter. But to avoid bringing in scala runtime...
if (java.util.Set.class.equals(a) || "interface scala.collection.Set".equals(a.toString())) {
return true;
}
}
}
}
return false;
}
@Override
public Model resolve(Type type, ModelConverterContext context, Iterator chain) {
if (chain.hasNext()) {
return chain.next().resolve(type, context, chain);
} else {
return null;
}
}
}