private void writeApis(Collection<ApiDeclaration> apis) throws IOException { List<ResourceListingAPI> resources = new LinkedList<ResourceListingAPI>(); File outputDirectory = this.options.getOutputDirectory(); Recorder recorder = this.options.getRecorder(); for (ApiDeclaration api : apis) { String resourcePath = api.getResourcePath(); if (!Strings.isNullOrEmpty(resourcePath)) { // make sure the filename for the resource is valid String resourceFile = ParserHelper.generateResourceFilename(resourcePath); resources.add( new ResourceListingAPI("/" + resourceFile + ".{format}", api.getDescription())); File apiFile = new File(outputDirectory, resourceFile + ".json"); recorder.record(apiFile, api); } } // write out json for the resource listing ResourceListing listing = new ResourceListing( SWAGGER_VERSION, this.options.getApiVersion(), this.options.getDocBasePath(), resources, this.options.getApiAuthorizations(), this.options.getApiInfo()); File docFile = new File(outputDirectory, "service.json"); recorder.record(docFile, listing); }
public boolean run() { try { // setup additional classes needed for processing, generally these are java ones such as // java.lang.String // adding them here allows them to be used in @outputType Collection<ClassDoc> typeClasses = new ArrayList<ClassDoc>(); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.String.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Integer.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Boolean.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Float.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Double.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Character.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Long.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Byte.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Date.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Calendar.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Map.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Collection.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Set.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.List.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.math.BigInteger.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.math.BigDecimal.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.UUID.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.DayOfWeek.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Duration.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Instant.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.LocalDate.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.LocalDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Month.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.MonthDay.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.OffsetDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.OffsetTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Period.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Year.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.YearMonth.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZoneId.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZoneOffset.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZonedDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.net.URI.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.net.URL.class.getName())); // filter the classes to process Collection<ClassDoc> docletClasses = new ArrayList<ClassDoc>(); for (ClassDoc classDoc : this.rootDoc.classes()) { // see if excluded via its FQN boolean excludeResource = false; if (this.options.getExcludeResourcePrefixes() != null && !this.options.getExcludeResourcePrefixes().isEmpty()) { for (String prefix : this.options.getExcludeResourcePrefixes()) { String className = classDoc.qualifiedName(); if (className.startsWith(prefix)) { excludeResource = true; break; } } } // see if the inclusion filter is set and if so this resource must match this if (!excludeResource && this.options.getIncludeResourcePrefixes() != null && !this.options.getIncludeResourcePrefixes().isEmpty()) { boolean matched = false; for (String prefix : this.options.getIncludeResourcePrefixes()) { String className = classDoc.qualifiedName(); if (className.startsWith(prefix)) { matched = true; break; } } excludeResource = !matched; } if (excludeResource) { continue; } // see if deprecated if (this.options.isExcludeDeprecatedResourceClasses() && ParserHelper.isDeprecated(classDoc, this.options)) { continue; } // see if excluded via a tag if (ParserHelper.hasTag(classDoc, this.options.getExcludeClassTags())) { continue; } docletClasses.add(classDoc); } ClassDocCache classCache = new ClassDocCache(docletClasses); List<ApiDeclaration> declarations = null; // build up set of subresources // do simple parsing to find sub resource classes // these are ones referenced in the return types of methods // which have a path but no http method Map<Type, ClassDoc> subResourceClasses = new HashMap<Type, ClassDoc>(); for (ClassDoc classDoc : docletClasses) { ClassDoc currentClassDoc = classDoc; while (currentClassDoc != null) { for (MethodDoc method : currentClassDoc.methods()) { // if the method has @Path but no Http method then its an entry point to a sub resource if (!ParserHelper.resolveMethodPath(method, this.options).isEmpty() && HttpMethod.fromMethod(method) == null) { ClassDoc subResourceClassDoc = classCache.findByType(method.returnType()); if (subResourceClassDoc != null) { if (this.options.isLogDebug()) { System.out.println( "Adding return type as sub resource class : " + subResourceClassDoc.name() + " for method " + method.name() + " of referencing class " + currentClassDoc.name()); } subResourceClasses.put(method.returnType(), subResourceClassDoc); } } } currentClassDoc = currentClassDoc.superclass(); // ignore parent object class if (!ParserHelper.hasAncestor(currentClassDoc)) { break; } } } // parse with the v2 parser that supports endpoints of the same resource being spread across // resource files Map<String, ApiDeclaration> resourceToDeclaration = new HashMap<String, ApiDeclaration>(); for (ClassDoc classDoc : docletClasses) { CrossClassApiParser classParser = new CrossClassApiParser( this.options, classDoc, docletClasses, subResourceClasses, typeClasses, SWAGGER_VERSION, this.options.getApiVersion(), this.options.getApiBasePath()); classParser.parse(resourceToDeclaration); } Collection<ApiDeclaration> declarationColl = resourceToDeclaration.values(); if (this.options.isLogDebug()) { System.out.println("After parse phase api declarations are: "); for (ApiDeclaration apiDec : declarationColl) { System.out.println( "Api Dec: base path " + apiDec.getBasePath() + ", res path: " + apiDec.getResourcePath()); for (Api api : apiDec.getApis()) { System.out.println("Api path:" + api.getPath()); for (Operation op : api.getOperations()) { System.out.println("Api nick name:" + op.getNickname() + " method " + op.getMethod()); } } } } // add any extra declarations if (this.options.getExtraApiDeclarations() != null && !this.options.getExtraApiDeclarations().isEmpty()) { declarationColl = new ArrayList<ApiDeclaration>(declarationColl); declarationColl.addAll(this.options.getExtraApiDeclarations()); } // set root path on any empty resources for (ApiDeclaration api : declarationColl) { if (api.getResourcePath() == null || api.getResourcePath().isEmpty() || api.getResourcePath().equals("/")) { api.setResourcePath(this.options.getResourceRootPath()); } } // merge the api declarations declarationColl = new ApiDeclarationMerger( SWAGGER_VERSION, this.options.getApiVersion(), this.options.getApiBasePath()) .merge(declarationColl); // clear any empty models for (ApiDeclaration api : declarationColl) { if (api.getModels() != null && api.getModels().isEmpty()) { api.setModels(null); } } declarations = new ArrayList<ApiDeclaration>(declarationColl); // sort the api declarations if needed if (this.options.isSortResourcesByPriority()) { Collections.sort( declarations, new Comparator<ApiDeclaration>() { public int compare(ApiDeclaration dec1, ApiDeclaration dec2) { return Integer.compare(dec1.getPriority(), dec2.getPriority()); } }); } else if (this.options.isSortResourcesByPath()) { Collections.sort( declarations, new Comparator<ApiDeclaration>() { public int compare(ApiDeclaration dec1, ApiDeclaration dec2) { if (dec1 == null || dec1.getResourcePath() == null) { return 1; } if (dec2 == null || dec2.getResourcePath() == null) { return -1; } return dec1.getResourcePath().compareTo(dec2.getResourcePath()); } }); } // sort apis of each declaration if (this.options.isSortApisByPath()) { for (ApiDeclaration dec : declarations) { if (dec.getApis() != null) { Collections.sort( dec.getApis(), new Comparator<Api>() { public int compare(Api o1, Api o2) { if (o1 == null || o1.getPath() == null) { return -1; } return o1.getPath().compareTo(o2.getPath()); } }); } } } writeApis(declarations); // Copy swagger-ui into the output directory. if (this.options.isIncludeSwaggerUi()) { copyUi(); } return true; } catch (IOException e) { System.err.println("Failed to write api docs, err msg: " + e.getMessage()); e.printStackTrace(); return false; } }