All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jboot.support.swagger.ControllerReaderExtension Maven / Gradle / Ivy

Go to download

Jboot is a similar SpringCloud project base on JFinal, Dubbo and Undertow.

There is a newer version: 4.1.6
Show newest version
/**
 * Copyright (c) 2015-2019, Michael Yang 杨福海 ([email protected]).
 * 

* 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 io.jboot.support.swagger; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import com.google.common.collect.Collections2; import com.jfinal.log.Log; import io.swagger.annotations.*; import io.swagger.converter.ModelConverters; import io.swagger.models.*; import io.swagger.models.parameters.*; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; import io.swagger.models.properties.RefProperty; import io.swagger.util.BaseReaderUtils; import io.swagger.util.ParameterProcessor; import io.swagger.util.PathUtils; import io.swagger.util.ReflectionUtils; import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.*; public class ControllerReaderExtension { private static final Log LOGGER = Log.getLog(ControllerReaderExtension.class); private static final String SUCCESSFUL_OPERATION = "successful operation"; private static List parseAnnotationValues(String str, Function processor) { final List result = new ArrayList(); for (String item : Splitter.on(",").trimResults().omitEmptyStrings().split(str)) { result.add(processor.apply(item)); } return result; } private static List parseStringValues(String str) { return parseAnnotationValues(str, new Function() { public String apply(String value) { return value; } }); } private static List parseSchemes(String schemes) { final List result = new ArrayList(); for (String item : StringUtils.trimToEmpty(schemes).split(",")) { final Scheme scheme = Scheme.forValue(StringUtils.trimToNull(item)); if (scheme != null && !result.contains(scheme)) { result.add(scheme); } } return result; } private static List parseAuthorizations(Authorization[] authorizations) { final List result = new ArrayList(); for (Authorization auth : authorizations) { if (StringUtils.isNotEmpty(auth.value())) { final SecurityRequirement security = new SecurityRequirement(); security.setName(auth.value()); for (AuthorizationScope scope : auth.scopes()) { if (StringUtils.isNotEmpty(scope.scope())) { security.addScope(scope.scope()); } } result.add(security); } } return result; } private static Map parseResponseHeaders(Swagger swagger, ReaderContext context, ResponseHeader[] headers) { Map responseHeaders = null; for (ResponseHeader header : headers) { final String name = header.name(); if (StringUtils.isNotEmpty(name)) { if (responseHeaders == null) { responseHeaders = new HashMap(); } final Class cls = header.response(); if (!ReflectionUtils.isVoid(cls)) { final Property property = ModelConverters.getInstance().readAsProperty(cls); if (property != null) { final Property responseProperty = ContainerWrapper.wrapContainer(header.responseContainer(), property, ContainerWrapper.ARRAY, ContainerWrapper.LIST, ContainerWrapper.SET); responseProperty.setDescription(header.description()); responseHeaders.put(name, responseProperty); appendModels(swagger, cls); } } } } return responseHeaders; } private static void appendModels(Swagger swagger, Type type) { final Map models = ModelConverters.getInstance().readAll(type); for (Map.Entry entry : models.entrySet()) { swagger.model(entry.getKey(), entry.getValue()); } } private static boolean isValidResponse(Type type) { final JavaType javaType = TypeFactory.defaultInstance().constructType(type); return !ReflectionUtils.isVoid(javaType); } private static Type getResponseType(Method method) { final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null && !ReflectionUtils.isVoid(apiOperation.response())) { return apiOperation.response(); } else { return method.getGenericReturnType(); } } private static String getResponseContainer(ApiOperation apiOperation) { return apiOperation == null ? null : StringUtils.defaultIfBlank(apiOperation.responseContainer(), null); } public int getPriority() { return 0; } public boolean isReadable(ReaderContext context) { final Api apiAnnotation = context.getCls().getAnnotation(Api.class); return apiAnnotation != null && (context.isReadHidden() || !apiAnnotation.hidden()); } public void applyConsumes(ReaderContext context, Operation operation, Method method) { final List consumes = new ArrayList(); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null) { consumes.addAll(parseStringValues(apiOperation.consumes())); } if (consumes.isEmpty()) { final Api apiAnnotation = context.getCls().getAnnotation(Api.class); if (apiAnnotation != null) { consumes.addAll(parseStringValues(apiAnnotation.consumes())); } consumes.addAll(context.getParentConsumes()); } for (String consume : consumes) { operation.consumes(consume); } } public void applyProduces(ReaderContext context, Operation operation, Method method) { final List produces = new ArrayList(); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null) { produces.addAll(parseStringValues(apiOperation.produces())); } if (produces.isEmpty()) { final Api apiAnnotation = context.getCls().getAnnotation(Api.class); if (apiAnnotation != null) { produces.addAll(parseStringValues(apiAnnotation.produces())); } produces.addAll(context.getParentProduces()); } for (String produce : produces) { operation.produces(produce); } } public String getHttpMethod(ReaderContext context, Method method) { final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); return apiOperation == null || StringUtils.isEmpty(apiOperation.httpMethod()) ? context.getParentHttpMethod() : apiOperation.httpMethod(); } public String getPath(ReaderContext context, Method method) { final Api apiAnnotation = context.getCls().getAnnotation(Api.class); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); final String operationPath = apiOperation == null ? null : apiOperation.nickname(); return PathUtils.collectPath(context.getParentPath(), apiAnnotation == null ? null : apiAnnotation.value(), StringUtils.isBlank(operationPath) ? method.getName() : operationPath); } public void applyOperationId(Operation operation, Method method) { final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null && StringUtils.isNotBlank(apiOperation.nickname())) { operation.operationId(apiOperation.nickname()); } else { operation.operationId(method.getName()); } } public void applySummary(Operation operation, Method method) { final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null && StringUtils.isNotBlank(apiOperation.value())) { operation.summary(apiOperation.value()); } } public void applyDescription(Operation operation, Method method) { final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null && StringUtils.isNotBlank(apiOperation.notes())) { operation.description(apiOperation.notes()); } } public void applySchemes(ReaderContext context, Operation operation, Method method) { final List schemes = new ArrayList(); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); final Api apiAnnotation = context.getCls().getAnnotation(Api.class); if (apiOperation != null) { schemes.addAll(parseSchemes(apiOperation.protocols())); } if (schemes.isEmpty() && apiAnnotation != null) { schemes.addAll(parseSchemes(apiAnnotation.protocols())); } for (Scheme scheme : schemes) { operation.scheme(scheme); } } public void setDeprecated(Operation operation, Method method) { operation.deprecated(ReflectionUtils.getAnnotation(method, Deprecated.class) != null); } public void applySecurityRequirements(ReaderContext context, Operation operation, Method method) { final List securityRequirements = new ArrayList(); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); final Api apiAnnotation = context.getCls().getAnnotation(Api.class); if (apiOperation != null) { securityRequirements.addAll(parseAuthorizations(apiOperation.authorizations())); } if (securityRequirements.isEmpty() && apiAnnotation != null) { securityRequirements.addAll(parseAuthorizations(apiAnnotation.authorizations())); } for (SecurityRequirement securityRequirement : securityRequirements) { operation.security(securityRequirement); } } public void applyTags(ReaderContext context, Operation operation, Method method) { final List tags = new ArrayList(); final Api apiAnnotation = context.getCls().getAnnotation(Api.class); if (apiAnnotation != null) { tags.addAll(Collections2.filter(Arrays.asList(apiAnnotation.tags()), new Predicate() { public boolean apply(String input) { return StringUtils.isNotBlank(input); } })); } tags.addAll(context.getParentTags()); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null) { tags.addAll(Collections2.filter(Arrays.asList(apiOperation.tags()), new Predicate() { public boolean apply(String input) { return StringUtils.isNotBlank(input); } })); } for (String tag : tags) { operation.tag(tag); } } public void applyResponses(Swagger swagger, ReaderContext context, Operation operation, Method method) { final Map result = new HashMap(); final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class); if (apiOperation != null && StringUtils.isNotBlank(apiOperation.responseReference())) { final Response response = new Response().description(SUCCESSFUL_OPERATION); response.schema(new RefProperty(apiOperation.responseReference())); result.put(apiOperation.code(), response); } final Type responseType = getResponseType(method); if (isValidResponse(responseType)) { final Property property = ModelConverters.getInstance().readAsProperty(responseType); if (property != null) { final Property responseProperty = ContainerWrapper.wrapContainer(getResponseContainer(apiOperation), property); final int responseCode = apiOperation == null ? 200 : apiOperation.code(); final Map defaultResponseHeaders = apiOperation == null ? Collections.emptyMap() : parseResponseHeaders(swagger, context, apiOperation.responseHeaders()); final Response response = new Response() .description(SUCCESSFUL_OPERATION) .schema(responseProperty) .headers(defaultResponseHeaders); result.put(responseCode, response); appendModels(swagger, responseType); } } final ApiResponses responseAnnotation = ReflectionUtils.getAnnotation(method, ApiResponses.class); if (responseAnnotation != null) { for (ApiResponse apiResponse : responseAnnotation.value()) { final Map responseHeaders = parseResponseHeaders(swagger, context, apiResponse.responseHeaders()); final Response response = new Response() .description(apiResponse.message()) .headers(responseHeaders); if (StringUtils.isNotEmpty(apiResponse.reference())) { response.schema(new RefProperty(apiResponse.reference())); } else if (!ReflectionUtils.isVoid(apiResponse.response())) { final Type type = apiResponse.response(); final Property property = ModelConverters.getInstance().readAsProperty(type); if (property != null) { response.schema(ContainerWrapper.wrapContainer(apiResponse.responseContainer(), property)); appendModels(swagger, type); } } result.put(apiResponse.code(), response); } } for (Map.Entry responseEntry : result.entrySet()) { if (responseEntry.getKey() == 0) { operation.defaultResponse(responseEntry.getValue()); } else { operation.response(responseEntry.getKey(), responseEntry.getValue()); } } } public void applyParameters(String httpMethod, ReaderContext context, Operation operation, Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation instanceof ApiParam) { ApiParam apiParam = (ApiParam) annotation; if ("get".equalsIgnoreCase(httpMethod)) { QueryParameter parameter = new QueryParameter(); parameter.setAccess(apiParam.access()); parameter.setName(apiParam.name()); parameter.setAllowEmptyValue(apiParam.allowEmptyValue()); parameter.setRequired(apiParam.required()); parameter.setDefault(apiParam.value()); parameter.setDefaultValue(apiParam.defaultValue()); parameter.setExample(apiParam.example()); parameter.setFormat(apiParam.format()); parameter.setCollectionFormat(apiParam.collectionFormat()); parameter.setDescription(apiParam.value()); operation.addParameter(parameter); } /** * post 请求 */ else if ("post".equalsIgnoreCase(httpMethod)) { BodyParameter parameter = new BodyParameter(); parameter.setAccess(apiParam.access()); parameter.setName(apiParam.name()); // parameter.setAllowEmptyValue(apiParam.allowEmptyValue()); parameter.setRequired(apiParam.required()); parameter.setDescription(apiParam.value()); Map examples = new HashMap<>(); Example example = apiParam.examples(); if (example != null) { ExampleProperty[] exampleProperties = example.value(); for (ExampleProperty ep : exampleProperties) { examples.put(ep.mediaType(), ep.value()); } } parameter.setExamples(examples); operation.addParameter(parameter); } } } } public void applyImplicitParameters(Swagger swagger, ReaderContext context, Operation operation, Method method) { final ApiImplicitParams implicitParams = method.getAnnotation(ApiImplicitParams.class); if (implicitParams != null && implicitParams.value().length > 0) { for (ApiImplicitParam param : implicitParams.value()) { final Parameter p = readImplicitParam(swagger, param); if (p != null) { operation.parameter(p); } } } } public void applyExtensions(ReaderContext context, Operation operation, Method method) { final ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); if (apiOperation != null) { operation.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(apiOperation.extensions())); } } private Parameter readImplicitParam(Swagger swagger, ApiImplicitParam param) { final Parameter p = ParameterFactory.createParam(param.paramType()); if (p == null) { return null; } final Type type = ReflectionUtils.typeFromString(param.dataType()); return ParameterProcessor.applyAnnotations(swagger, p, type == null ? String.class : type, Collections.singletonList(param)); } enum ParameterFactory { PATH("path") { protected Parameter create() { return new PathParameter(); } }, QUERY("query") { protected Parameter create() { return new QueryParameter(); } }, FORM("form") { protected Parameter create() { return new FormParameter(); } }, FORM_DATA("formData") { protected Parameter create() { return new FormParameter(); } }, HEADER("header") { protected Parameter create() { return new HeaderParameter(); } }, BODY("body") { protected Parameter create() { return new BodyParameter(); } }; private final String paramType; ParameterFactory(String paramType) { this.paramType = paramType; } public static Parameter createParam(String paramType) { for (ParameterFactory item : values()) { if (item.paramType.equalsIgnoreCase(paramType)) { return item.create(); } } LOGGER.warn("Unknown implicit parameter type: [" + paramType + "]"); return null; } protected abstract Parameter create(); } enum ContainerWrapper { LIST("list") { protected Property doWrap(Property property) { return new ArrayProperty(property); } }, ARRAY("array") { protected Property doWrap(Property property) { return new ArrayProperty(property); } }, MAP("map") { protected Property doWrap(Property property) { return new MapProperty(property); } }, SET("set") { protected Property doWrap(Property property) { ArrayProperty arrayProperty = new ArrayProperty(property); arrayProperty.setUniqueItems(true); return arrayProperty; } }; private final String container; ContainerWrapper(String container) { this.container = container; } public static Property wrapContainer(String container, Property property, ContainerWrapper... allowed) { final Set tmp = allowed.length > 0 ? EnumSet.copyOf(Arrays.asList(allowed)) : EnumSet.allOf(ContainerWrapper.class); for (ContainerWrapper wrapper : tmp) { final Property prop = wrapper.wrap(container, property); if (prop != null) { return prop; } } return property; } public Property wrap(String container, Property property) { if (this.container.equalsIgnoreCase(container)) { return doWrap(property); } return null; } protected abstract Property doWrap(Property property); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy