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

springfox.javadoc.doclet.SwaggerPropertiesDoclet Maven / Gradle / Ivy

/*
 *
 *  Copyright 2018-2019 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.javadoc.doclet;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import springfox.javadoc.plugin.JavadocBuilderPlugin;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

import static springfox.javadoc.doclet.DocletOptionParser.*;

// the NOSONAR comment is added to ignore sonar warning about usage of Sun classes
// because doclets can only be written using Sun classes

/**
 * Generate properties file based on Javadoc.
 * 

* The generated properties file will then be read by the * {@link JavadocBuilderPlugin} to enhance the Swagger documentation. * * @author rgoers * @author MartinNeumannBeTSE */ public class SwaggerPropertiesDoclet { public static final String SPRINGFOX_JAVADOC_PROPERTIES = "META-INF/springfox.javadoc.properties"; private static final String REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping"; private static final String REQUEST_GET_MAPPING = "org.springframework.web.bind.annotation.RequestMethod.GET"; private static final String REQUEST_POST_MAPPING = "org.springframework.web.bind.annotation.RequestMethod.POST"; private static final String REQUEST_PUT_MAPPING = "org.springframework.web.bind.annotation.RequestMethod.PUT"; private static final String REQUEST_PATCH_MAPPING = "org.springframework.web.bind.annotation.RequestMethod.PATCH"; private static final String REQUEST_DELETE_MAPPING = "org.springframework.web.bind.annotation.RequestMethod.DELETE"; private static final String DELETE_MAPPING = "org.springframework.web.bind.annotation.DeleteMapping"; private static final String GET_MAPPING = "org.springframework.web.bind.annotation.GetMapping"; private static final String PATCH_MAPPING = "org.springframework.web.bind.annotation.PatchMapping"; private static final String POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping"; private static final String PUT_MAPPING = "org.springframework.web.bind.annotation.PutMapping"; private static final String RETURN = "@return"; private static final String PATH = "path"; private static final String VALUE = "value"; private static final String NEWLINE = "\n"; private static final String EMPTY = ""; private static final String METHOD = "method"; private static final String[] MAPPINGS = new String[] { DELETE_MAPPING, GET_MAPPING, PATCH_MAPPING, POST_MAPPING, PUT_MAPPING, REQUEST_MAPPING }; private static final String[][] REQUEST_MAPPINGS = new String[][] { { REQUEST_DELETE_MAPPING, "DELETE" }, { REQUEST_GET_MAPPING, "GET" }, { REQUEST_PATCH_MAPPING, "PATCH" }, { REQUEST_POST_MAPPING, "POST" }, { REQUEST_PUT_MAPPING, "PUT" } }; private static DocletOptions docletOptions; private SwaggerPropertiesDoclet() { throw new UnsupportedOperationException(); } /** * See Using * custom command-line options * @param option option evaluate an expected length for a given option * @return number of options */ @SuppressWarnings("WeakerAccess") public static int optionLength(String option) { int length = 0; if (option.equalsIgnoreCase(CLASS_DIR_OPTION)) { length = 2; } if (option.equalsIgnoreCase(EXCEPTION_REF_OPTION)) { length = 2; } return length; } /** * See Using * custom command-line options * @param options command line options split as key value pairs on index 0 and 1 * @param reporter reporter for errors * @return true if options are valid */ @SuppressWarnings("WeakerAccess") public static boolean validOptions( String[][] options, DocErrorReporter reporter) { DocletOptionParser parser = new DocletOptionParser(options); try { docletOptions = parser.parse(); return true; } catch (IllegalStateException e) { reporter.printError(e.getMessage()); } return false; } /** * See A * Simple Example Doclet * @param root {@link RootDoc} * @return true if it started successfully */ @SuppressWarnings({ "unused", "WeakerAccess", "UnusedReturnValue" }) public static boolean start(RootDoc root) { String propertyFilePath = docletOptions.getPropertyFilePath(); if (propertyFilePath == null || propertyFilePath.length() == 0) { root.printError("No output location was specified"); return false; } else { StringBuilder sb = new StringBuilder(propertyFilePath); if (!propertyFilePath.endsWith("/")) { sb.append("/"); } sb.append(SPRINGFOX_JAVADOC_PROPERTIES); String out = sb.toString(); root.printNotice("Writing output to " + out); File file = new File(out); //noinspection ResultOfMethodCallIgnored file.getParentFile().mkdirs(); OutputStream javadoc = null; try { javadoc = new FileOutputStream(file); Properties properties = new Properties(); for (ClassDoc classDoc : root.classes()) { sb.setLength(0); String defaultRequestMethod = processClass(classDoc, sb); String pathRoot = sb.toString(); for (MethodDoc methodDoc : classDoc.methods()) { processMethod( properties, methodDoc, defaultRequestMethod, pathRoot, docletOptions.isDocumentExceptions()); } } properties.store(javadoc, "Springfox javadoc properties"); } catch (IOException e) { root.printError(e.getMessage()); } finally { if (javadoc != null) { try { javadoc.close(); } catch (IOException e) { // close for real } } } } return true; } private static String processClass( ClassDoc classDoc, StringBuilder pathRoot) { String defaultRequestMethod = null; for (AnnotationDesc annotationDesc : classDoc.annotations()) { if (REQUEST_MAPPING.equals(annotationDesc.annotationType().qualifiedTypeName())) { for (AnnotationDesc.ElementValuePair pair : annotationDesc.elementValues()) { if (VALUE.equals(pair.element().name()) || PATH.equals(pair.element().name())) { setRoot(pathRoot, pair); } if (METHOD.equals(pair.element().name())) { defaultRequestMethod = pair.value().toString(); } } break; } } return defaultRequestMethod; } private static void setRoot( StringBuilder pathRoot, AnnotationDesc.ElementValuePair pair) { String value = pair.value().toString().replaceAll("\"$|^\"", ""); if (!value.startsWith("/")) { pathRoot.append("/"); } if (value.endsWith("/")) { pathRoot.append(value, 0, value.length() - 1); } else { pathRoot.append(value); } } private static void processMethod( Properties properties, MethodDoc methodDoc, String defaultRequestMethod, String pathRoot, boolean exceptionRef) { for (AnnotationDesc annotationDesc : methodDoc.annotations()) { String annotationType = annotationDesc.annotationType().toString(); if (isMapping(annotationType)) { StringBuilder path = new StringBuilder(pathRoot); for (AnnotationDesc.ElementValuePair pair : annotationDesc.elementValues()) { if (VALUE.equals(pair.element().name()) || PATH.equals(pair.element().name())) { appendPath(path, pair); break; } } if (!path.substring(path.length() - 1).equals(".")) { path.append("."); } String requestMethod = getRequestMethod(annotationDesc, annotationType, defaultRequestMethod); if (requestMethod != null) { path.append(requestMethod); saveProperty(properties, path.toString() + ".notes", methodDoc.commentText()); for (ParamTag paramTag : methodDoc.paramTags()) { saveProperty(properties, path.toString() + ".param." + paramTag.parameterName(), paramTag.parameterComment()); } for (Tag tag : methodDoc.tags()) { if (tag.name().equals(RETURN)) { saveProperty(properties, path.toString() + ".return", tag.text()); break; } } if (exceptionRef) { processThrows(properties, methodDoc.throwsTags(), path); } } } } } private static void appendPath( StringBuilder path, AnnotationDesc.ElementValuePair pair) { String value = pair.value().toString().replaceAll("\"$|^\"", ""); if (value.startsWith("/")) { path.append(value).append("."); } else { path.append("/").append(value).append("."); } } private static boolean isMapping(String name) { for (String mapping : MAPPINGS) { if (mapping.equals(name)) { return true; } } return false; } private static String getRequestMethod( AnnotationDesc annotationDesc, String name, String defaultRequestMethod) { if (REQUEST_MAPPING.equals(name)) { for (AnnotationDesc.ElementValuePair pair : annotationDesc.elementValues()) { if (METHOD.equals(pair.element().name())) { return resolveRequestMethod(pair, defaultRequestMethod); } } } else if (PUT_MAPPING.equals(name)) { return "PUT"; } else if (POST_MAPPING.equals(name)) { return "POST"; } else if (PATCH_MAPPING.equals(name)) { return "PATCH"; } else if (GET_MAPPING.equals(name)) { return "GET"; } else if (DELETE_MAPPING.equals(name)) { return "DELETE"; } return defaultRequestMethod; } private static String resolveRequestMethod( AnnotationDesc.ElementValuePair pair, String defaultRequestMethod) { String value = pair.value().toString(); for (String[] each : REQUEST_MAPPINGS) { if (each[0].equals(value)) { return each[1]; } } return defaultRequestMethod; } private static void processThrows( Properties properties, ThrowsTag[] throwsTags, StringBuilder path) { for (int i = 0; i < throwsTags.length; i++) { String key = path.toString() + ".throws." + i; String value = throwsTags[i].exceptionType().typeName() + "-" + throwsTags[i].exceptionComment(); saveProperty(properties, key, value); } } private static void saveProperty( Properties properties, String key, String value) { value = value.replaceAll(NEWLINE, EMPTY); if (value.length() > 0) { properties.setProperty(key, value); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy