栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

为龙目岛创建自定义注释

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为龙目岛创建自定义注释

一般注意事项

如果您已经在使用Lombok,则可以添加自定义Lombok转换批注和处理程序。

  1. 使用

    @Target(FIELD)
    和定义存在注释
    @Retention(SOURCE)

  2. 创建一个处理程序

    @ProviderFor(JavacAnnotationHandler.class)

    public class HandleExists extends JavacAnnotationHandler{ …`

处理您的注释。处理程序类包必须以

lombok.
前缀开头。如果除了javac之外还需要支持Eclipse等,则需要编写更多的处理程序来扩展适当的框架类。

  1. 在处理程序中,重写/实现是
    handle()
    通过AST操纵生成所需代码的方法。

您可以将@Getter实现作为示例:

注释:
Getter.java

处理程序:
HandleGetter.java

您还可以查看其他注释和处理程序的源,以了解如何生成特定代码。

您需要添加对Lombok(JDK tools.jar)的依赖。


一些资源:

  • 在龙目岛,皮克与一帮自龙目注释的源项目,特别是FluentSetter.java,HandleFluentSetter.java / FluentSetterHandler.java

  • 自定义转换概述

  • 具有说明的简单注释示例。


注意,这里有几点要考虑

  • 这是一堆要编写和维护的重要代码。如果您打算使用注释5至6次,那是不值得的。
  • 您可能需要通过lombok升级来更改注释处理器的实现。
  • lombok所依赖的编译器中的漏洞也可能被关闭(然后整个Lombok项目将发生巨大变化或不复存在;在这种情况下,如果您广泛使用Lombok,即使是@Getter,也将遇到更严重的问题)。

没有Lombok的更复杂的替代方案是使用标准注释处理进行代码生成,但是AFAIK,您不能更改原始类,而必须生成/使用扩展它们的类(除非您将使用与 Lombok
相同的后门或手段到CGLib或ASM之类的代码操作)。


龙目岛的例子

以下是一些用于创建自定义Lombok批注的工作代码,我将其称为 @Contains

它只是Javac实现,没有Eclipse等。我想为Eclipse或其他IDE创建类似的处理程序并不难。

它将生成 fieldName Contains()成员方法,该成员方法委派给 fieldName .contains()。

请注意,该代码只是快速而肮脏(但可以正常工作)的示例。对于生产级注释,您将需要处理许多边界条件,检查正确的类型,处理Lombok配置等,因为可以在lombok或lombok-
pg库源代码中看到它。


样本用法


SomeEnity.java

@Getter@Setterpublic class SomeEntity {    @NonNull    @Contains    private Collection<String> fieldOne = new ArrayList<>();    @NonNull    @Contains    private Collection<String> fieldTwo = new ArrayList<>();}

SomeEntityTest.java

public class SomeEntityTest {    @Test    public void test() {        SomeEntity entity = new SomeEntity();        Collection<String> test1 = Arrays.asList(new String[] { "1", "2" });        entity.setFieldOne(test1);        assertSame(test1, entity.getFieldOne());        Collection<String> test2 = new HashSet<String>(Arrays.asList(new String[] { "3", "4" }));        entity.setFieldTwo(test2);        assertSame(test2, entity.getFieldTwo());        assertTrue(entity.fieldoneContains("1"));        assertTrue(entity.fieldoneContains("2"));        assertFalse(entity.fieldoneContains("3"));        assertFalse(entity.fieldoneContains("4"));        assertFalse(entity.fieldTwoContains("1"));        assertFalse(entity.fieldTwoContains("2"));        assertTrue(entity.fieldTwoContains("3"));        assertTrue(entity.fieldTwoContains("4"));        try { entity.setFieldOne(null); fail("exception expected");        } catch (Exception ex) {        }        try { entity.setFieldTwo(null); fail("exception expected");        } catch (Exception ex) {        }    }}

注释实现


包含.java

@Target({ElementType.FIELD})@Retention(RetentionPolicy.SOURCE)public @interface Contains {    Class<?>[] types() default {};    Class<?>[] excludes() default {};}

HandleContains.java

@ProviderFor(JavacAnnotationHandler.class) @HandlerPriority(65536) @ResolutionResetNeeded public class HandleContains extends JavacAnnotationHandler<Contains> {    @Override     public void handle(AnnotationValues<Contains> annotation, JCAnnotation ast, JavacNode annotationNode) {        try { JavacNode node = annotationNode.up(); if (node.getKind() != Kind.FIELD) {     annotationNode.addError("@Contains is allowed only on fields");     return; } Name delegateName = annotationNode.toname(node.getName()); JavacResolution reso = new JavacResolution(annotationNode.getContext()); JCTree member = node.get(); if (member.type == null) {     reso.resolveClassMember(node); } Type delegateType = member.type; if (delegateType instanceof ClassType) {     ClassType ct = (ClassType) delegateType;     //TODO validate that this field is a collection type     // if(!Collection)     //   annotationNode.addError("@Contains can only be used on collections");     final String methodName = "contains";     MethodSig methodSig = getMethodBinding(methodName, ct, annotationNode.getTypesUtil());     if (methodSig == null) throw new Exception("no method " + methodName + " in " + ct.tsym.name);     JCMethodDecl methodDecl = createDelegateMethod(methodSig, annotationNode, delegateName);     injectMethod(node.up(), methodDecl); } else {     annotationNode.addError("@Contains can only use concrete class types");     return; }        } catch (Exception ex) { //ex.printStackTrace(); annotationNode.addError("@Contains unexpected error: " + ex.getMessage());        }    }    public JCMethodDecl createDelegateMethod(MethodSig sig, JavacNode annotation, Name delegateName) throws TypeNotConvertibleException {        JavacTreeMaker maker = annotation.getTreeMaker();        com.sun.tools.javac.util.List<JCAnnotation> annotations;        if (sig.isDeprecated) { annotations = com.sun.tools.javac.util.List.of(maker.Annotation(genJavaLangTypeRef(annotation, "Deprecated"), com.sun.tools.javac.util.List.<JCexpression>nil()));        } else { annotations = com.sun.tools.javac.util.List.nil();        }        JCModifiers mods = maker.Modifiers(PUBLIC, annotations);        JCexpression returnType = JavacResolution.typeToJCTree((Type) sig.type.getReturnType(), annotation.getAst(), true);        boolean useReturn = sig.type.getReturnType().getKind() != TypeKind.VOID;        ListBuffer<JCVariableDecl> params = sig.type.getParameterTypes().isEmpty() ? null : new ListBuffer<JCVariableDecl>();        ListBuffer<JCexpression> args = sig.type.getParameterTypes().isEmpty() ? null : new ListBuffer<JCexpression>();        ListBuffer<JCexpression> thrown = sig.type.getThrownTypes().isEmpty() ? null : new ListBuffer<JCexpression>();        ListBuffer<JCTypeParameter> typeParams = sig.type.getTypeVariables().isEmpty() ? null : new ListBuffer<JCTypeParameter>();        ListBuffer<JCexpression> typeArgs = sig.type.getTypeVariables().isEmpty() ? null : new ListBuffer<JCexpression>();        Types types = Types.instance(annotation.getContext());        for (TypeMirror param : sig.type.getTypeVariables()) { Name name = ((TypeVar) param).tsym.name; ListBuffer<JCexpression> bounds = new ListBuffer<JCexpression>(); for (Type type : types.getBounds((TypeVar) param)) {     bounds.append(JavacResolution.typeToJCTree(type, annotation.getAst(), true)); } typeParams.append(maker.TypeParameter(name, bounds.toList())); typeArgs.append(maker.Ident(name));        }        for (TypeMirror ex : sig.type.getThrownTypes()) { thrown.append(JavacResolution.typeToJCTree((Type) ex, annotation.getAst(), true));        }        int idx = 0;        String[] paramNames = sig.getParameterNames();        boolean varargs = sig.elem.isVarArgs();        for (TypeMirror param : sig.type.getParameterTypes()) { long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, annotation.getContext()); JCModifiers paramMods = maker.Modifiers(flags); Name name = annotation.toname(paramNames[idx++]); if (varargs && idx == paramNames.length) {     paramMods.flags |= VARARGS; } params.append(maker.VarDef(paramMods, name, JavacResolution.typeToJCTree((Type) param, annotation.getAst(), true), null)); args.append(maker.Ident(name));        }        JCexpression accessor = maker.Select(maker.Ident(annotation.toname("this")), delegateName);        JCexpression delegateCall = maker.Apply(toList(typeArgs), maker.Select(accessor, sig.name), toList(args));        JCStatement body = useReturn ? maker.Return(delegateCall) : maker.Exec(delegateCall);        JCBlock bodyBlock = maker.Block(0, com.sun.tools.javac.util.List.of(body));        StringBuilder generatedMethodName = new StringBuilder(delegateName);        generatedMethodName.append(sig.name.toString());        generatedMethodName.setCharAt(delegateName.length(), Character.toUpperCase(generatedMethodName.charAt(delegateName.length())));        return recursiveSetGeneratedBy(maker.MethodDef(mods, annotation.toname(generatedMethodName.toString()), returnType, toList(typeParams), toList(params), toList(thrown), bodyBlock, null), annotation.get(), annotation.getContext());    }    public static <T> com.sun.tools.javac.util.List<T> toList(ListBuffer<T> collection) {        return collection == null ? com.sun.tools.javac.util.List.<T>nil() : collection.toList();    }    public static class MethodSig {        final Name name;        final ExecutableType type;        final boolean isDeprecated;        final ExecutableElement elem;        MethodSig(Name name, ExecutableType type, boolean isDeprecated, ExecutableElement elem) { this.name = name; this.type = type; this.isDeprecated = isDeprecated; this.elem = elem;        }        String[] getParameterNames() { List<? extends VariableElement> paramList = elem.getParameters(); String[] paramNames = new String[paramList.size()]; for (int i = 0; i < paramNames.length; i++) {     paramNames[i] = paramList.get(i).getSimpleName().toString(); } return paramNames;        }        @Override public String toString() { return (isDeprecated ? "@Deprecated " : "") + name + " " + type;        }    }    public MethodSig getMethodBinding(String name, ClassType ct, JavacTypes types) {        MethodSig result = null;        TypeSymbol tsym = ct.asElement();        if (tsym == null) throw new IllegalArgumentException("no class");        for (Symbol member : tsym.getEnclosedElements()) { if (member.getKind() != ElementKind.METHOD || !name.equals(member.name.toString())) {     continue; } if (member.isStatic()) continue; if (member.isConstructor()) continue; ExecutableElement exElem = (ExecutableElement) member; if (!exElem.getModifiers().contains(Modifier.PUBLIC)) continue; ExecutableType methodType = (ExecutableType) types.asMemberOf(ct, member); boolean isDeprecated = (member.flags() & DEPRECATED) != 0; result = new MethodSig(member.name, methodType, isDeprecated, exElem);        }        if (result == null) { if (ct.supertype_field instanceof ClassType) {     result = getMethodBinding(name, (ClassType) ct.supertype_field, types); } if (result == null) {     if (ct.interfaces_field != null) {         for (Type iface : ct.interfaces_field) {  if (iface instanceof ClassType) {      result = getMethodBinding(name, (ClassType) iface, types);      if (result != null) {          break;      }  }         }     } }        }        return result;    }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/419133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号