/**
   * Adds the necessary field and methods to support resource locating.
   *
   * @param declaringClass the class to which we add the support field and methods
   */
  public static void apply(@Nonnull ClassNode declaringClass, @Nullable String beanName) {
    injectInterface(declaringClass, EVENT_PUBLISHER_CNODE);

    FieldNode epField =
        injectField(
            declaringClass, EVENT_ROUTER_FIELD_NAME, PRIVATE, EVENT_PUBLISHER_FIELD_CNODE, null);

    Parameter erParam = param(EVENT_ROUTER_CNODE, EVENT_ROUTER_PROPERTY);
    if (!isBlank(beanName)) {
      AnnotationNode namedAnnotation = new AnnotationNode(NAMED_TYPE);
      namedAnnotation.addMember("value", new ConstantExpression(beanName));
      erParam.addAnnotation(namedAnnotation);
    }

    MethodNode setter =
        new MethodNode(
            METHOD_SET_EVENT_ROUTER,
            PRIVATE,
            VOID_TYPE,
            params(erParam),
            NO_EXCEPTIONS,
            stmnt(call(field(epField), METHOD_SET_EVENT_ROUTER, args(var(EVENT_ROUTER_PROPERTY)))));
    setter.addAnnotation(new AnnotationNode(INJECT_TYPE));
    injectMethod(declaringClass, setter);

    addDelegateMethods(declaringClass, EVENT_PUBLISHER_CNODE, field(epField));
  }
  private void checkForConvenienceForm(AnnotationNode node, boolean exclude) {
    Object val = node.getMember("value");
    if (val == null || !(val instanceof ConstantExpression)) return;
    Object allParts = ((ConstantExpression) val).getValue();
    if (!(allParts instanceof String)) return;
    String allstr = (String) allParts;

    // strip off trailing attributes
    boolean done = false;
    while (!done) {
      Matcher attrs = ATTRIBUTES_PATTERN.matcher(allstr);
      if (attrs.find()) {
        String attrName = attrs.group(2);
        String attrValue = attrs.group(3);
        if (attrName == null || attrValue == null) continue;
        boolean isBool = GRAB_BOOLEAN.contains(attrName);
        ConstantExpression value =
            new ConstantExpression(isBool ? Boolean.valueOf(attrValue) : attrValue);
        value.setSourcePosition(node);
        node.addMember(attrName, value);
        int lastSemi = allstr.lastIndexOf(';');
        if (lastSemi == -1) {
          allstr = "";
          break;
        }
        allstr = allstr.substring(0, lastSemi);
      } else {
        done = true;
      }
    }

    if (allstr.contains("#")) {
      // see: http://ant.apache.org/ivy/history/latest-milestone/textual.html
      Matcher m = IVY_PATTERN.matcher(allstr);
      if (!m.find()) return;
      if (m.group(1) == null || m.group(2) == null) return;
      node.addMember("module", new ConstantExpression(m.group(2)));
      node.addMember("group", new ConstantExpression(m.group(1)));
      if (m.group(6) != null) node.addMember("conf", new ConstantExpression(m.group(6)));
      if (m.group(4) != null) node.addMember("version", new ConstantExpression(m.group(4)));
      else if (!exclude && node.getMember("version") == null)
        node.addMember("version", new ConstantExpression("*"));
      node.getMembers().remove("value");
    } else if (allstr.contains(":")) {
      // assume gradle syntax
      // see:
      // http://www.gradle.org/latest/docs/userguide/dependency_management.html#sec:how_to_declare_your_dependencies
      Map<String, Object> parts = GrapeUtil.getIvyParts(allstr);
      for (String key : parts.keySet()) {
        String value = parts.get(key).toString();
        if (!key.equals("version") || !value.equals("*") || !exclude) {
          node.addMember(key, new ConstantExpression(value));
        }
      }
      node.getMembers().remove("value");
    }
  }
  /**
   * Copies all <tt>candidateAnnotations</tt> with retention policy {@link
   * java.lang.annotation.RetentionPolicy#RUNTIME} and {@link
   * java.lang.annotation.RetentionPolicy#CLASS}.
   *
   * <p>Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not
   * supported at present.
   */
  public static void copyAnnotatedNodeAnnotations(
      final AnnotatedNode annotatedNode,
      final List<AnnotationNode> copied,
      List<AnnotationNode> notCopied) {
    List<AnnotationNode> annotationList = annotatedNode.getAnnotations();
    for (AnnotationNode annotation : annotationList) {

      List<AnnotationNode> annotations =
          annotation.getClassNode().getAnnotations(AbstractASTTransformation.RETENTION_CLASSNODE);
      if (annotations.isEmpty()) continue;

      if (hasClosureMember(annotation)) {
        notCopied.add(annotation);
        continue;
      }

      AnnotationNode retentionPolicyAnnotation = annotations.get(0);
      Expression valueExpression = retentionPolicyAnnotation.getMember("value");
      if (!(valueExpression instanceof PropertyExpression)) continue;

      PropertyExpression propertyExpression = (PropertyExpression) valueExpression;
      boolean processAnnotation =
          propertyExpression.getProperty() instanceof ConstantExpression
              && ("RUNTIME"
                      .equals(((ConstantExpression) (propertyExpression.getProperty())).getValue())
                  || "CLASS"
                      .equals(
                          ((ConstantExpression) (propertyExpression.getProperty())).getValue()));

      if (processAnnotation) {
        AnnotationNode newAnnotation = new AnnotationNode(annotation.getClassNode());
        for (Map.Entry<String, Expression> member : annotation.getMembers().entrySet()) {
          newAnnotation.addMember(member.getKey(), member.getValue());
        }
        newAnnotation.setSourcePosition(annotatedNode);

        copied.add(newAnnotation);
      }
    }
  }
 private AnnotationNode createGrabAnnotation() {
   ClassNode classNode = new ClassNode(Grab.class);
   AnnotationNode annotationNode = new AnnotationNode(classNode);
   annotationNode.addMember("value", new ConstantExpression("spring-core"));
   return annotationNode;
 }