
com.haz4j.swagger.ReflectionUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swagger4jsonrpc Show documentation
Show all versions of swagger4jsonrpc Show documentation
This project is implementation of swagger for JSON-RPC with Spring Boot.
It generates UI that helps delelopers test api and share it with colleagues
The newest version!
package com.haz4j.swagger;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.googlecode.jsonrpc4j.JsonRpcParam;
import com.googlecode.jsonrpc4j.JsonRpcService;
import com.haz4j.swagger.annotation.Api;
import com.haz4j.swagger.annotation.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import sun.reflect.generics.parser.SignatureParser;
import sun.reflect.generics.repository.ClassRepository;
import sun.reflect.generics.tree.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.TypeVariable;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class ReflectionUtils {
private static Field methodSignature;
private static Field classTypeSignaturePath;
private static Field arrayTypeSignatureComponentType;
private static Field fieldSignature;
private static Field classGenericInfo;
static {
init();
}
@SneakyThrows
public static void init() {
log.debug("init");
methodSignature = Method.class.getDeclaredField("signature");
classTypeSignaturePath = ClassTypeSignature.class.getDeclaredField("path");
arrayTypeSignatureComponentType = ArrayTypeSignature.class.getDeclaredField("componentType");
fieldSignature = Field.class.getDeclaredField("signature");
classGenericInfo = Class.class.getDeclaredField("genericInfo");
methodSignature.setAccessible(true);
classTypeSignaturePath.setAccessible(true);
arrayTypeSignatureComponentType.setAccessible(true);
fieldSignature.setAccessible(true);
classGenericInfo.setAccessible(true);
}
public static String getJsonRpcParam(Parameter parameter) {
log.debug("getJsonRpcParam: parameter - " + parameter);
JsonRpcParam[] jsonRpcParams = parameter.getAnnotationsByType(JsonRpcParam.class);
if (jsonRpcParams != null
&& jsonRpcParams.length > 0
&& jsonRpcParams[0] != null
&& !StringUtils.isEmpty(jsonRpcParams[0].value())
) {
return jsonRpcParams[0].value();
} else {
return parameter.getName();
}
}
public static String getJsonProperty(Field field) {
log.debug("getJsonProperty: field - " + field);
JsonProperty[] jsonProperties = field.getAnnotationsByType(JsonProperty.class);
if (jsonProperties != null
&& jsonProperties.length > 0
&& jsonProperties[0] != null
&& !StringUtils.isEmpty(jsonProperties[0].value())) {
return jsonProperties[0].value();
}
return field.getName();
}
@SneakyThrows
public static Optional getRealType(Field field, @NotNull Map genericTypeArgs) {
log.debug("getRealType: field - " + field + ", genericTypeArgs - " + genericTypeArgs);
// signature = TR;
Optional signature = ReflectionUtils.getSignature(field);
return signature.map(s -> genericTypeArgs.get(signature.get()))
.map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.map(realClass -> TypeUtils.getRawType(realClass, null));
}
@SneakyThrows
public static Optional getSignature(Field field) {
log.debug("getSignature: field - " + field);
String signature = (String) fieldSignature.get(field); //for "R" it will be "TR;"
return Optional.ofNullable(signature).map(s -> signature.substring(1, signature.length() - 1));
}
public static String getDescription(Method method) {
log.debug("getDescription: method - " + method);
return Optional
.ofNullable(method.getAnnotation(ApiOperation.class))
.map(ApiOperation::value)
.orElse("");
}
@SneakyThrows
public static List getTypeWrappers(Method method) {
log.debug("getTypeWrappers: method - " + method);
String signature = (String) methodSignature.get(method);
if (signature == null) {
return new ArrayList<>();
}
MethodTypeSignature methodTypeSignature = SignatureParser.make().parseMethodSig(signature);
TypeSignature[] parameterTypes = methodTypeSignature.getParameterTypes();
return Arrays.stream(parameterTypes)
.map(p -> toTypeWrapper(p))
.collect(Collectors.toList());
}
@SneakyThrows
private static TypeWrapper toTypeWrapper(TypeSignature parameterType) {
log.debug("toTypeWrapper: parameterType - " + parameterType);
TypeWrapper typeWrapper = null;
if (ArrayTypeSignature.class.isAssignableFrom(parameterType.getClass())) {
ClassTypeSignature classTypeSignature = (ClassTypeSignature) arrayTypeSignatureComponentType.get(parameterType);
//this is array, thus we call the same method with element as a parameter
return toTypeWrapper(classTypeSignature);
}
ArrayList paths = (ArrayList) classTypeSignaturePath.get(parameterType);
for (Object o : paths) {
SimpleClassTypeSignature signature = (SimpleClassTypeSignature) o;
TypeArgument[] typeArguments = signature.getTypeArguments();
List childs = Arrays.stream(typeArguments)
.map(ta -> toTypeWrapper((TypeSignature) ta))
.collect(Collectors.toList());
typeWrapper = new TypeWrapper(signature.getName(), childs);
}
return typeWrapper;
}
public static String getPath(Class api) {
log.debug("getPath: api" + api);
JsonRpcService jsonRpcService = (JsonRpcService) api.getAnnotation(JsonRpcService.class);
return Optional.ofNullable(jsonRpcService)
.map(JsonRpcService::value)
.map(path -> path.replace("//", "/"))
.orElseThrow(() -> new RuntimeException("Class " + api + " is annotated with @Api " +
"and should be annotated @JsonRpcService(value) with non-empty value"));
}
@SneakyThrows
public static List> getTypeParams(Class> type) {
log.debug("getTypeParams: type - " + type);
return Optional.ofNullable((ClassRepository) classGenericInfo.get(type))
.map(classRepository -> classRepository.getTypeParameters())
.map(tp -> Arrays.asList(tp))
.orElse(new ArrayList<>());
}
public static Pair getTag(Class api) {
log.debug("getTag: api - " + api);
Api apiAnnotation = (Api) api.getAnnotation(Api.class);
if (apiAnnotation != null && apiAnnotation.tags().length > 0) {
String tagName = apiAnnotation.tags()[0];
String tagValue = apiAnnotation.value();
return Pair.of(tagName, tagValue);
}
return Pair.of("default", "");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy