com.ly.doc.utils.DocClassUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smart-doc Show documentation
Show all versions of smart-doc Show documentation
Smart-doc is a tool that supports both JAVA RESTFUL API and Apache Dubbo RPC interface document
generation.
/*
* Copyright (C) 2018-2023 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.ly.doc.utils;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import com.ly.doc.model.ApiReturn;
import com.power.common.util.StringUtil;
import com.ly.doc.filter.ReturnTypeProcessor;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
/**
* Description:
* Doc class handle util
*
* @author yu 2018//14.
*/
public class DocClassUtil {
/**
* get class names by generic class name
*
* @param typeName generic class name
* @return array of string
*/
public static String[] getSimpleGicName(String typeName) {
if (JavaClassValidateUtil.isCollection(typeName)) {
typeName = typeName + "";
} else if (JavaClassValidateUtil.isArray(typeName)) {
typeName = typeName.substring(0, typeName.lastIndexOf("["));
typeName = "java.util.List<" + typeName + ">";
} else if (JavaClassValidateUtil.isMap(typeName)) {
typeName = typeName + "";
}
if (typeName.contains("<")) {
String pre = typeName.substring(0, typeName.indexOf("<"));
if (JavaClassValidateUtil.isMap(pre)) {
return getMapKeyValueType(typeName);
}
if (JavaClassValidateUtil.isCollection(pre)) {
String type = typeName.substring(typeName.indexOf("<") + 1, typeName.lastIndexOf(">"));
return type.split(" ");
}
String[] arr = Arrays.stream(getGicName(typeName))
.map(str -> str.split(","))
.map(Arrays::asList)
.flatMap(Collection::stream)
.toArray(String[]::new);
return classNameFix(arr);
} else {
return new String[0];
}
}
/**
* get class names by generic class name.
* "controller.R$Data" =====> ["T,A", "T,A"]
* @param typeName generic class name
* @return array of string
*/
static String[] getGicName(String typeName) {
StringBuilder builder = new StringBuilder(typeName.length());
List ginNameList = new ArrayList<>();
int ltLen = 0;
for (char c : typeName.toCharArray()) {
if (c == '<' || c == '>') {
ltLen += (c == '<') ? 1 : -1;
// Skip the outermost symbols <
if (c == '<' && ltLen == 1) {
continue;
}
}
if (ltLen > 0) {
builder.append(c);
} else if (ltLen == 0 && c == '>') {
ginNameList.add(builder.toString());
builder.setLength(0);
}
}
return ginNameList.toArray(new String[0]);
}
/**
* Get a simple type name from a generic class name
*
* @param gicName Generic class name
* @return String
*/
public static String getSimpleName(String gicName) {
// remove strings contained in '< >' and < >. e.g. controller.R$Data =====> controller.R$Data
StringBuilder builder = new StringBuilder(gicName.length());
int ltLen = 0;
for (char c : gicName.toCharArray()) {
if (c == '<' || c == '>') {
ltLen += (c == '<') ? 1 : -1;
} else if (ltLen <= 0) {
builder.append(c);
}
}
return builder.toString();
}
/**
* Automatic repair of generic split class names
*
* @param arr arr of class name
* @return array of String
*/
private static String[] classNameFix(String[] arr) {
List classes = new ArrayList<>();
List indexList = new ArrayList<>();
int globIndex = 0;
int length = arr.length;
for (int i = 0; i < length; i++) {
if (classes.size() > 0) {
int index = classes.size() - 1;
if (!isClassName(classes.get(index))) {
globIndex = globIndex + 1;
if (globIndex < length) {
indexList.add(globIndex);
String className = classes.get(index) + "," + arr[globIndex];
classes.set(index, className);
}
} else {
globIndex = globIndex + 1;
if (globIndex < length) {
if (isClassName(arr[globIndex])) {
indexList.add(globIndex);
classes.add(arr[globIndex]);
} else {
if (!indexList.contains(globIndex) && !indexList.contains(globIndex + 1)) {
indexList.add(globIndex);
classes.add(arr[globIndex] + "," + arr[globIndex + 1]);
globIndex = globIndex + 1;
indexList.add(globIndex);
}
}
}
}
} else {
if (isClassName(arr[i])) {
indexList.add(i);
classes.add(arr[i]);
} else {
if (!indexList.contains(i) && !indexList.contains(i + 1)) {
globIndex = i + 1;
classes.add(arr[i] + "," + arr[globIndex]);
indexList.add(i);
indexList.add(i + 1);
}
}
}
}
return classes.toArray(new String[0]);
}
/**
* get map key and value type name populate into array.
*
* @param gName generic class name
* @return array of string
*/
public static String[] getMapKeyValueType(String gName) {
if (StringUtil.isEmpty(gName)) {
return new String[0];
}
if (gName.contains("<")) {
String[] arr = new String[2];
String key = gName.substring(gName.indexOf("<") + 1, gName.indexOf(","));
String value = gName.substring(gName.indexOf(",") + 1, gName.lastIndexOf(">"));
arr[0] = key;
arr[1] = value;
return arr;
} else {
return new String[0];
}
}
/**
* Convert the parameter types exported to the api document
*
* @param javaTypeName java simple typeName
* @return String
*/
public static String processTypeNameForParams(String javaTypeName) {
if (StringUtil.isEmpty(javaTypeName)) {
return "object";
}
if (javaTypeName.length() == 1) {
return "object";
}
if (javaTypeName.contains("[]")) {
return "array";
}
javaTypeName = javaTypeName.toLowerCase();
switch (javaTypeName) {
case "java.lang.string":
case "string":
case "char":
case "java.util.date":
case "date":
case "java.util.uuid":
case "uuid":
case "localdatetime":
case "java.time.localdatetime":
case "java.time.localdate":
case "java.time.localtime":
case "java.time.year":
case "java.time.yearmonth":
case "java.time.monthday":
case "java.time.period":
case "localdate":
case "offsetdatetime":
case "localtime":
case "timestamp":
case "zoneddatetime":
case "period":
case "java.time.zoneddatetime":
case "java.time.offsetdatetime":
case "java.sql.timestamp":
case "java.lang.character":
case "character":
case "org.bson.types.objectid":
return "string";
case "java.util.list":
case "list":
case "java.util.set":
case "set":
case "java.util.linkedlist":
case "linkedlist":
case "java.util.arraylist":
case "arraylist":
case "java.util.treeset":
case "treeset":
return "array";
case "java.lang.byte":
case "byte":
return "int8";
case "java.lang.integer":
case "integer":
case "int":
return "int32";
case "short":
case "java.lang.short":
return "int16";
case "double":
case "java.lang.double":
return "double";
case "java.lang.long":
case "long":
return "int64";
case "java.lang.float":
case "float":
return "float";
case "java.math.bigdecimal":
case "bigdecimal":
case "biginteger":
return "number";
case "java.lang.boolean":
case "boolean":
return "boolean";
case "map":
return "map";
case "multipartfile":
return "file";
default:
return "object";
}
}
/**
* process return type
*
* @param fullyName fully name
* @return ApiReturn
*/
public static ApiReturn processReturnType(String fullyName) {
ReturnTypeProcessor processor = new ReturnTypeProcessor();
processor.setTypeName(fullyName);
return processor.process();
}
/**
* rewrite request param
*
* @param typeName param type name
* @return String
*/
public static String rewriteRequestParam(String typeName) {
switch (typeName) {
case "org.springframework.data.domain.Pageable":
return "com.ly.doc.model.framework.PageableAsQueryParam";
default:
return typeName;
}
}
private static boolean isClassName(String className) {
className = className.replaceAll("[^<>]", "");
Stack stack = new Stack<>();
for (char c : className.toCharArray()) {
if (c == '<') {
stack.push('>');
} else if (stack.isEmpty() || c != stack.pop()) {
return false;
}
}
return stack.isEmpty();
}
/**
* Get class annotations
*
* @param cls JavaClass
* @return List of JavaAnnotation
*/
public static List getAnnotations(JavaClass cls) {
JavaClass superClass = cls.getSuperJavaClass();
List classAnnotations = new ArrayList<>();
try {
if (Objects.nonNull(superClass)) {
classAnnotations.addAll(superClass.getAnnotations());
}
} catch (Throwable e) {
throw new RuntimeException("Could not obtain annotations for class: " + cls.getFullyQualifiedName() + "\n" + e);
}
classAnnotations.addAll(cls.getAnnotations());
return classAnnotations;
}
public static T newInstance(Class classWithNoArgsConstructor) {
try {
return classWithNoArgsConstructor.getConstructor().newInstance();
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
InstantiationException e) {
throw new IllegalArgumentException("Class must have the NoArgsConstructor");
}
}
}