com.gitee.l0km.codegen.base.AnnotationHelper Maven / Gradle / Ivy
package com.gitee.l0km.codegen.base;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.RepeatableContainers;
import org.springframework.stereotype.Component;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ValueConstants;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.gitee.l0km.casban.CasbanScanners;
import com.gitee.l0km.codegen.annotations.DeriveMethod;
import com.gitee.l0km.codegen.annotations.ServicePort;
import com.gitee.l0km.codegen.base.Method.Parameter;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.gdface.utils.AnnotationProxy;
import net.gdface.utils.TypeNameUtils;
import net.gdface.utils.TypeNameUtils.FullName;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.base.Strings.commonPrefix;
public class AnnotationHelper {
private static class Singleton{
/**
* 要排除的注释类型
*/
private static final ImmutableSet> BUILTIN_EXCLUDE_ANNOTATIONS;
/**
* 要排除的注释类的包名
*/
private static final ImmutableSet BUILTIN_EXCLUDE_ANNOT_PACKAGES;
/**
* 要排除的注释类的类全名
*/
public static final ImmutableSet BUILTIN_EXCLUDE_ANNOT_CLASSENAMES;
static {
BUILTIN_EXCLUDE_ANNOTATIONS = ImmutableSet.>builder()
.add(SuppressWarnings.class)
.add(DeriveMethod.class)
.add(ServicePort.class)
.add(ApiOperation.class)
.add(ResponseBody.class)
.add(ApiImplicitParams.class)
.add(Component.class)
.add(Configuration.class)
.add(DependsOn.class)
.build();
/** 以'*'结尾代表包含子包名 */
BUILTIN_EXCLUDE_ANNOT_PACKAGES = ImmutableSet.builder()
.add("javax.validation.*")
.add("org.aspectj.lang.annotation.")
.add("gu.sql2java.annotations.")
.add("com.gitee.l0km.casban.annotations.")
.build();
BUILTIN_EXCLUDE_ANNOT_CLASSENAMES = ImmutableSet.builder()
.add("com.gitee.l0km.aocache.annotations.AoCacheable")
.add("com.gitee.l0km.aocache.annotations.AoWeakCacheable")
.add("com.gitee.l0km.aocache.annotations.AoClear")
.add("com.gitee.l0km.aocache.annotations.AoClears")
.build();
}
}
private Set excludeAnnotations = Sets.newHashSet();
public Set getExcludeAnnotations() {
return excludeAnnotations;
}
public void setExcludeAnnotations(Set excludeAnnotations) {
if(null != excludeAnnotations && !excludeAnnotations.isEmpty()){
this.excludeAnnotations = excludeAnnotations;
}
}
private boolean withExcludePackage(Annotation a) {
String pkg = a.annotationType().getPackage().getName();
if(Singleton.BUILTIN_EXCLUDE_ANNOT_PACKAGES.contains(pkg)) {
return true;
}
return Singleton.BUILTIN_EXCLUDE_ANNOT_PACKAGES
.stream().anyMatch(p->p.endsWith("*") &&
commonPrefix(p, pkg).equals(p.substring(0, p.indexOf('*'))));
}
public boolean isExcludeAnnotation(Annotation a){
return Singleton.BUILTIN_EXCLUDE_ANNOTATIONS.contains(a.annotationType())
|| Singleton.BUILTIN_EXCLUDE_ANNOT_CLASSENAMES.contains(a.annotationType().getName())
|| withExcludePackage(a)
|| (null != excludeAnnotations && excludeAnnotations.contains(a.annotationType().getName()));
}
public boolean isFieldAnnotation(Annotation a) {
if(null != a) {
Target target =a.annotationType().getAnnotation(Target.class);
if(null == target) {
return true;
}
return Iterables.tryFind(Arrays.asList(target.value()),e->ElementType.FIELD.equals(e)).isPresent();
}
return false;
}
public AnnotationProxy extends Annotation> normalizeAnnotation(Method method,Annotation annot){
if(null != method && null != annot){
@SuppressWarnings({ "rawtypes", "unchecked" })
AnnotationProxy rma = new AnnotationProxy(annot);
return rma;
}
return null;
}
public AnnotationProxy extends Annotation> normalizeAnnotation(AnnotatedElement element,Annotation annot){
if(null != element && null != annot){
@SuppressWarnings({ "rawtypes", "unchecked" })
AnnotationProxy rma = new AnnotationProxy(annot);
return rma;
}
return null;
}
/**
* 返回 {@link AnnotatedElement} 上所有不使用casban AliasFor注解的注解[不重复]
* @param element
* @param searchStrategy 参见 {@link SearchStrategy}
*/
private static ImmutableList> allNocasbanMergedAnnoationsOf(
AnnotatedElement element, String searchStrategy){
if(null != element){
MergedAnnotations mergedAnnotations = MergedAnnotations.from(element,
SearchStrategy.valueOf(searchStrategy), RepeatableContainers.none());
/** 所有非没有使用 casban AliasFor 注解的注解类型 */
List> nometa = mergedAnnotations.stream()
.filter(a->!a.isMetaPresent())
.filter(a->!CasbanScanners.withCasbanAliasFor(a.getType()))
.collect(Collectors.toList());
return ImmutableList.copyOf(nometa);
}
return ImmutableList.of();
}
/**
* 返回{@link AnnotatedElement} 上所有使用casban AliasFor注解的注解[不重复]
* @param element
* @param searchStrategy 参见 {@link SearchStrategy}
*/
private static ImmutableList>
allCasbanMergedAnnoationsOf(AnnotatedElement element, String searchStrategy){
if(null != element){
com.gitee.l0km.common.spring.core.annotation.MergedAnnotations mergedAnnotations=
com.gitee.l0km.common.spring.core.annotation.TypeMappedAnnotations
.from(element,
com.gitee.l0km.common.spring.core.annotation.MergedAnnotations.SearchStrategy.valueOf(searchStrategy),
com.gitee.l0km.common.spring.core.annotation.RepeatableContainers.none());
Set> nometa = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(mergedAnnotations.iterator(), Spliterator.ORDERED), false)
.filter(a->!a.isMetaPresent())
.filter(a->CasbanScanners.withCasbanAliasFor(a.getType()))
.collect(Collectors.toSet());
return ImmutableList.copyOf(nometa);
}
return ImmutableList.of();
}
/**
* 返回方法上所有不使用casban AliasFor注解的注解类型
* @param method
*/
private ImmutableList> allNocasbanAnnoationsOf(Method method){
if(null != method){
ImmutableList> mergedAnnotations = allNocasbanMergedAnnoationsOf(method.delegate(), "SUPERCLASS");
return ImmutableList.copyOf(mergedAnnotations.stream()
.map(c->c.synthesize())
.map(a->normalizeAnnotation(method, a))
.collect(Collectors.toList()));
}
return ImmutableList.of();
}
/**
* 返回方法上所有使用casban AliasFor注解的注解类型
* @param method
* @param searchStrategy 参见 {@link SearchStrategy}
*/
private ImmutableList> allCasbanAnnoationsOf(Method method, String searchStrategy){
if(null != method){
ImmutableList> mergedAnnotations =
allCasbanMergedAnnoationsOf(method.delegate(), searchStrategy);
return ImmutableList.copyOf(mergedAnnotations.stream()
.map(c->c.synthesize())
.map(a->normalizeAnnotation(method, a))
.collect(Collectors.toList()));
}
return ImmutableList.of();
}
/**
* 返回方法上所有注解(不重复)包含父类注解
* @param element
* @param searchStrategy 参见 {@link SearchStrategy}
*/
@AoWeakCacheable
private ImmutableList> allAnnoationsOf(AnnotatedElement element, String searchStrategy){
if(null != element){
List> annotationProxys =
allNocasbanMergedAnnoationsOf(element, searchStrategy).stream()
.map(c->c.synthesize())
.map(a->normalizeAnnotation(element, a))
.collect(Collectors.toList());
List> casbanAnnotationProxys =
allCasbanMergedAnnoationsOf(element, searchStrategy).stream()
.map(c->c.synthesize())
.map(a->normalizeAnnotation(element, a))
.collect(Collectors.toList());
return FluentIterable.from(annotationProxys)
.append(casbanAnnotationProxys)
.toSortedList((o1,o2)->o1.annotationType().getName().compareTo(o2.annotationType().getName()));
}
return ImmutableList.of();
}
/**
* 返回方法上所有注解(不重复)包含父类注解
* @param method
* @param searchStrategy 参见 {@link SearchStrategy}
*/
@AoWeakCacheable
private ImmutableList> allAnnoationsOf(Method method, String searchStrategy){
if(null != method){
ImmutableList> annotations = allNocasbanAnnoationsOf(method);
return FluentIterable.from(annotations)
.append(allCasbanAnnoationsOf(method, searchStrategy))
.toList();
}
return ImmutableList.of();
}
/**
* @since 2.3.0
*/
public List> annotationOf(AnnotatedElement element, String searchStrategy){
return allAnnoationsOf(element, searchStrategy).stream()
.filter(a->!isExcludeAnnotation(a))
.sorted((l,r)->l.annotationType().getName().compareTo(r.annotationType().getName()))
.collect(Collectors.toList());
}
public List> annotationOf(Method method, String searchStrategy){
return allAnnoationsOf(method, searchStrategy).stream()
.filter(a->!isExcludeAnnotation(a))
.sorted((l,r)->l.annotationType().getName().compareTo(r.annotationType().getName()))
.collect(Collectors.toList());
}
public List> annotationOf(Parameter parameter){
if(null != parameter){
return parameter.getAnnotations().stream().map(a->new AnnotationProxy<>(a))
.filter(a->!isExcludeAnnotation(a)&& isFieldAnnotation(a))
.sorted((l,r)->l.annotationType().getName().compareTo(r.annotationType().getName()))
.collect(Collectors.toList());
}
return ImmutableList.of();
}
private static IterableasClassNames(Iterable> input,FullName fn){
return FluentIterable.from(input).transform(ap->ap.toString(c->TypeNameUtils.getTypeName((Type)c, fn)));
}
public String annoationCodeOf(Parameter parameter,String delim, FullName fn){
return Joiner.on(MoreObjects.firstNonNull(delim, " ")).join(asClassNames(annotationOf(parameter),fn));
}
public String annoationCodeOf(Method method,String delim, String searchStrategy, FullName fn){
return Joiner.on(MoreObjects.firstNonNull(delim, "\n ")).join(asClassNames(annotationOf(method, searchStrategy),fn));
}
/**
* @param fn
* @since 2.3.0
*/
public String annoationCodeOf(AnnotatedElement element,String delim, String searchStrategy, FullName fn){
return Joiner.on(MoreObjects.firstNonNull(delim, "\n ")).join(asClassNames(annotationOf(element, searchStrategy),fn));
}
/**
* 将方法中的注释引用的类添加到import class中
* @param element
* @param searchStrategy 参见 {@link SearchStrategy}
*/
public LinkedHashSet annotationClassOf(AnnotatedElement element, String searchStrategy) {
// 将方法中的注释引用的类添加到import class中
LinkedHashSet classes = Sets.newLinkedHashSet();
List> annots = Lists.newLinkedList(allAnnoationsOf(element, searchStrategy));
Iterable> filtered = Iterables.filter(annots,
a->!isExcludeAnnotation(a));
classes.addAll(Sets.newHashSet(Iterables.transform(filtered, p->p.annotationType())));
filtered.forEach(p->classes.addAll(p.getImportedClasses()));
return classes;
}
/**
* 将方法中的注释引用的类添加到import class中
* @param method
* @param includeParameter 是否包括参数注解
* @param searchStrategy 参见 {@link SearchStrategy}
*/
public LinkedHashSet annotationClassOf(Method method, boolean includeParameter, String searchStrategy) {
// 将方法中的注释引用的类添加到import class中
LinkedHashSet classes = Sets.newLinkedHashSet();
List> annots = Lists.newLinkedList(allAnnoationsOf(method, searchStrategy));
if(includeParameter) {
for(Annotation[] z1:method.getParameterAnnotations()){
annots.addAll(Lists.transform(Arrays.asList(z1), a->new AnnotationProxy<>(a)));
}
}
Iterable> filtered = Iterables.filter(annots,
a->!isExcludeAnnotation(a));
classes.addAll(Sets.newHashSet(Iterables.transform(filtered, p->p.annotationType())));
filtered.forEach(p->classes.addAll(p.getImportedClasses()));
return classes;
}
/**
* 判断方法上是否有 {@code annotationType} 指定的注解
* @since 2.3.0
*/
public boolean withAnnotation(Method method,String annotationType, String searchStrategy) {
return annotationOf(method,searchStrategy)
.stream()
.anyMatch(p->p.annotationType().getName().equals(annotationType));
}
/**
* 判断 {@link AnnotatedElement} 上是否有 {@code annotationType} 指定的注解
* @since 2.3.0
*/
public boolean withAnnotation(AnnotatedElement element,String annotationType, String searchStrategy) {
return annotationOf(element,searchStrategy)
.stream()
.anyMatch(p->p.annotationType().getName().equals(annotationType));
}
/**
* @since 2.3.0
*/
public boolean withAnnotation(Method method,Class extends Annotation>annotationType, String searchStrategy) {
return null == annotationType? false: withAnnotation(method,annotationType.getName(),searchStrategy);
}
/**
* @since 2.3.0
*/
public boolean withAnnotation(AnnotatedElement element,Class extends Annotation>annotationType, String searchStrategy) {
return null == annotationType? false: withAnnotation(element,annotationType.getName(),searchStrategy);
}
/**
* 返回指定方法的{@link RequestMapping}注释中的method字段,如果为{@code null}则返回默认值{@code defaultValue}
* @param method
* @param defaultValue 默认值
* @return {@code method}为{@code null}则返回{@code defaultValue}
*/
public String requestMethodOf(Method method, String defaultValue){
defaultValue = Strings.isNullOrEmpty(defaultValue)?"POST" : defaultValue;
RequestMapping rma = AnnotatedElementUtils.findMergedAnnotation(method.delegate(), RequestMapping.class);
if(null != method && null != rma){
RequestMapping annot = new AnnotationProxy(rma).createAnnotation();
RequestMethod[] value = annot.method();
return (null != value && value.length>0)? value[0].name() : defaultValue;
}
return defaultValue;
}
/**
* 返回指定方法的{@link RequestMapping}注释中的produces字段,如果为{@code null}则返回空字符串
* @param method
* @return {@code method}为{@code null}则返回空字符串
*/
@AoWeakCacheable
public String producesOf(Method method){
RequestMapping rma;
if(null != method && null != (rma = method.getAnnotation(RequestMapping.class))){
String[] produces = rma.produces();
return Joiner.on(',').join(Iterables.filter(Arrays.asList(produces),s->!Strings.isNullOrEmpty(s)));
}
return "";
}
public String appendProducesIfNoempty(Method method){
String produces = producesOf(method);
if(!produces.isEmpty()){
return String.format(",produces=\"%s\"", produces);
}
return "";
}
private static ImmutableSet STREAM_CONTANT_TYPES=ImmutableSet.of("application/octet-stream","application/pdf");
public boolean needResponse(Method method){
String produces = producesOf(method);
return produces.isEmpty() ? true : !Iterables.tryFind(STREAM_CONTANT_TYPES, s->produces.indexOf(s)>=0).isPresent();
}
public String defaultValueOf(Parameter parameter){
RequestParam rpa;
if(null != parameter && null != (rpa = parameter.getAnnotation(RequestParam.class))){
RequestParam annot = new AnnotationProxy(rpa).createAnnotation();
String value = annot.defaultValue();
return !ValueConstants.DEFAULT_NONE.equals(value) ? value : null;
}
return null;
}
public String defaultValueCodeOf(Parameter parameter,String left){
left = nullToEmpty(left);
String defaultValue = defaultValueOf(parameter);
if(null != defaultValue){
return left + "defaultValue=\"" + defaultValue + "\"";
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy