Esempio n. 1
0
  public void testMethods() throws Exception {
    ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
    classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));

    Statement statementA = new ReturnStatement(new ConstantExpression("calledA"));
    Statement statementB = new ReturnStatement(new ConstantExpression("calledB"));
    Statement emptyStatement = new BlockStatement();

    classNode.addMethod(
        new MethodNode(
            "a",
            ACC_PUBLIC,
            ClassHelper.OBJECT_TYPE,
            Parameter.EMPTY_ARRAY,
            ClassNode.EMPTY_ARRAY,
            statementA));
    classNode.addMethod(
        new MethodNode(
            "b", ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementB));

    classNode.addMethod(
        new MethodNode(
            "noReturnMethodA",
            ACC_PUBLIC,
            null,
            Parameter.EMPTY_ARRAY,
            ClassNode.EMPTY_ARRAY,
            emptyStatement));
    classNode.addMethod(
        new MethodNode(
            "noReturnMethodB",
            ACC_PUBLIC,
            ClassHelper.OBJECT_TYPE,
            Parameter.EMPTY_ARRAY,
            ClassNode.EMPTY_ARRAY,
            emptyStatement));

    classNode.addMethod(
        new MethodNode(
            "c",
            ACC_PUBLIC,
            ClassHelper.VOID_TYPE,
            Parameter.EMPTY_ARRAY,
            ClassNode.EMPTY_ARRAY,
            emptyStatement));

    Class fooClass = loadClass(classNode);
    assertTrue("Loaded a new class", fooClass != null);

    Object bean = fooClass.newInstance();
    assertTrue("Created instance of class: " + bean, bean != null);

    assertCallMethod(bean, "a", "calledA");
    assertCallMethod(bean, "b", "calledB");
    assertCallMethod(bean, "noReturnMethodA", null);
    assertCallMethod(bean, "noReturnMethodB", null);
    assertCallMethod(bean, "c", null);
  }
Esempio n. 2
0
 public static void doCast(MethodVisitor mv, Class type) {
   if (type == Object.class) return;
   if (type.isPrimitive() && type != Void.TYPE) {
     unbox(mv, type);
   } else {
     mv.visitTypeInsn(
         CHECKCAST,
         type.isArray()
             ? BytecodeHelper.getTypeDescription(type)
             : BytecodeHelper.getClassInternalName(type.getName()));
   }
 }
Esempio n. 3
0
 private void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class clazz) {
   Type[] interfaceTypes = clazz.getGenericInterfaces();
   if (interfaceTypes.length == 0) {
     classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
   } else {
     Class[] interfaceClasses = clazz.getInterfaces();
     ClassNode[] ret = new ClassNode[interfaceTypes.length];
     for (int i = 0; i < interfaceTypes.length; i++) {
       ret[i] = makeClassNode(cu, interfaceTypes[i], interfaceClasses[i]);
     }
     classNode.setInterfaces(ret);
   }
 }
Esempio n. 4
0
 private ClassNode configureClass(Class c) {
   if (c.isPrimitive()) {
     return ClassHelper.make(c);
   } else {
     return ClassHelper.makeWithoutCaching(c, false);
   }
 }
  @SuppressWarnings("Unchecked")
  public static Object checkImmutable(Class<?> clazz, String fieldName, Object field) {
    Immutable immutable = (Immutable) clazz.getAnnotation(MY_CLASS);
    List<Class> knownImmutableClasses = new ArrayList<Class>();
    if (immutable != null && immutable.knownImmutableClasses().length > 0) {
      knownImmutableClasses = Arrays.asList(immutable.knownImmutableClasses());
    }

    if (field == null
        || field instanceof Enum
        || inImmutableList(field.getClass().getName())
        || knownImmutableClasses.contains(field.getClass())) return field;
    if (field instanceof Collection) return DefaultGroovyMethods.asImmutable((Collection) field);
    if (field.getClass().getAnnotation(MY_CLASS) != null) return field;
    final String typeName = field.getClass().getName();
    throw new RuntimeException(
        createErrorMessage(clazz.getName(), fieldName, typeName, "constructing"));
  }
  @SuppressWarnings("unchecked")
  public <T extends Enum> T getEnumMemberValue(
      AnnotationNode node, String name, Class<T> type, T defaultValue) {
    if (node == null) return defaultValue;

    final PropertyExpression member = (PropertyExpression) node.getMember(name);
    if (member == null) return defaultValue;

    if (!type.equals(member.getObjectExpression().getType().getTypeClass())) return defaultValue;

    try {
      String value = member.getPropertyAsString();
      Method fromString = type.getMethod("valueOf", String.class);
      return (T) fromString.invoke(null, value);
    } catch (Exception e) {
      return defaultValue;
    }
  }
Esempio n. 7
0
 private ClassNode makeClassNode(CompileUnit cu, Type t, Class c) {
   ClassNode back = null;
   if (cu != null) back = cu.getClass(c.getName());
   if (back == null) back = ClassHelper.make(c);
   if (!(t instanceof Class)) {
     ClassNode front = configureType(t);
     front.setRedirect(back);
     return front;
   }
   return back;
 }
Esempio n. 8
0
 private void configureAnnotation(AnnotationNode node, Annotation annotation) {
   Class type = annotation.annotationType();
   if (type == Retention.class) {
     Retention r = (Retention) annotation;
     RetentionPolicy value = r.value();
     setRetentionPolicy(value, node);
     node.setMember(
         "value",
         new PropertyExpression(
             new ClassExpression(ClassHelper.makeWithoutCaching(RetentionPolicy.class, false)),
             value.toString()));
   } else if (type == Target.class) {
     Target t = (Target) annotation;
     ElementType[] elements = t.value();
     ListExpression elementExprs = new ListExpression();
     for (ElementType element : elements) {
       elementExprs.addExpression(
           new PropertyExpression(
               new ClassExpression(ClassHelper.ELEMENT_TYPE_TYPE), element.name()));
     }
     node.setMember("value", elementExprs);
   } else {
     Method[] declaredMethods = type.getDeclaredMethods();
     for (int i = 0; i < declaredMethods.length; i++) {
       Method declaredMethod = declaredMethods[i];
       try {
         Object value = declaredMethod.invoke(annotation);
         Expression valueExpression = annotationValueToExpression(value);
         if (valueExpression == null) continue;
         node.setMember(declaredMethod.getName(), valueExpression);
       } catch (IllegalAccessException e) {
       } catch (InvocationTargetException e) {
       }
     }
   }
 }
Esempio n. 9
0
  public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) {
    Class clazz = classNode.getTypeClass();
    Field[] fields = clazz.getDeclaredFields();
    for (Field f : fields) {
      ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType());
      classNode.addField(f.getName(), f.getModifiers(), ret, null);
    }
    Method[] methods = clazz.getDeclaredMethods();
    for (Method m : methods) {
      ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType());
      Parameter[] params =
          makeParameters(compileUnit, m.getGenericParameterTypes(), m.getParameterTypes());
      ClassNode[] exceptions =
          makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes());
      MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null);
      setMethodDefaultValue(mn, m);
      setAnnotationMetaData(m.getAnnotations(), mn);
      mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
      classNode.addMethod(mn);
    }
    Constructor[] constructors = clazz.getDeclaredConstructors();
    for (Constructor ctor : constructors) {
      Parameter[] params =
          makeParameters(compileUnit, ctor.getGenericParameterTypes(), ctor.getParameterTypes());
      ClassNode[] exceptions =
          makeClassNodes(compileUnit, ctor.getGenericExceptionTypes(), ctor.getExceptionTypes());
      classNode.addConstructor(ctor.getModifiers(), params, exceptions, null);
    }

    Class sc = clazz.getSuperclass();
    if (sc != null)
      classNode.setUnresolvedSuperClass(
          makeClassNode(compileUnit, clazz.getGenericSuperclass(), sc));
    makeInterfaceTypes(compileUnit, classNode, clazz);
    setAnnotationMetaData(classNode.getTypeClass().getAnnotations(), classNode);

    PackageNode packageNode = classNode.getPackage();
    if (packageNode != null) {
      setAnnotationMetaData(classNode.getTypeClass().getPackage().getAnnotations(), packageNode);
    }
  }
Esempio n. 10
0
 /** Generates the bytecode to unbox the current value on the stack */
 public static void unbox(MethodVisitor mv, Class type) {
   if (type.isPrimitive() && type != Void.TYPE) {
     String returnString = "(Ljava/lang/Object;)" + BytecodeHelper.getTypeDescription(type);
     mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, type.getName() + "Unbox", returnString);
   }
 }
  /**
   * Main loop entry.
   *
   * <p>First, it delegates to the super visitClass so we can collect the relevant annotations in an
   * AST tree walk.
   *
   * <p>Second, it calls the visit method on the transformation for each relevant annotation found.
   *
   * @param classNode the class to visit
   */
  public void visitClass(ClassNode classNode) {
    // only descend if we have annotations to look for
    Map<Class<? extends ASTTransformation>, Set<ASTNode>> baseTransforms =
        classNode.getTransforms(phase);
    if (!baseTransforms.isEmpty()) {
      final Map<Class<? extends ASTTransformation>, ASTTransformation> transformInstances =
          new HashMap<Class<? extends ASTTransformation>, ASTTransformation>();
      for (Class<? extends ASTTransformation> transformClass : baseTransforms.keySet()) {
        try {
          transformInstances.put(transformClass, transformClass.newInstance());
        } catch (InstantiationException e) {
          source
              .getErrorCollector()
              .addError(
                  new SimpleMessage(
                      "Could not instantiate Transformation Processor "
                          + transformClass, // + " declared by " +
                                            // annotation.getClassNode().getName(),
                      source));
        } catch (IllegalAccessException e) {
          source
              .getErrorCollector()
              .addError(
                  new SimpleMessage(
                      "Could not instantiate Transformation Processor "
                          + transformClass, // + " declared by " +
                                            // annotation.getClassNode().getName(),
                      source));
        }
      }

      // invert the map, is now one to many
      transforms = new HashMap<ASTNode, List<ASTTransformation>>();
      for (Map.Entry<Class<? extends ASTTransformation>, Set<ASTNode>> entry :
          baseTransforms.entrySet()) {
        for (ASTNode node : entry.getValue()) {
          List<ASTTransformation> list = transforms.get(node);
          if (list == null) {
            list = new ArrayList<ASTTransformation>();
            transforms.put(node, list);
          }
          list.add(transformInstances.get(entry.getKey()));
        }
      }

      targetNodes = new LinkedList<ASTNode[]>();

      // first pass, collect nodes
      super.visitClass(classNode);

      // second pass, call visit on all of the collected nodes
      for (ASTNode[] node : targetNodes) {
        for (ASTTransformation snt : transforms.get(node[0])) {
          if (snt instanceof CompilationUnitAware) {
            ((CompilationUnitAware) snt).setCompilationUnit(context.getCompilationUnit());
          }
          snt.visit(node, source);
        }
      }
    }
  }
 private static void addPhaseOperationsForGlobalTransforms(
     CompilationUnit compilationUnit, Map<String, URL> transformNames, boolean isFirstScan) {
   GroovyClassLoader transformLoader = compilationUnit.getTransformLoader();
   for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
     try {
       Class gTransClass = transformLoader.loadClass(entry.getKey(), false, true, false);
       // no inspection unchecked
       GroovyASTTransformation transformAnnotation =
           (GroovyASTTransformation) gTransClass.getAnnotation(GroovyASTTransformation.class);
       if (transformAnnotation == null) {
         compilationUnit
             .getErrorCollector()
             .addWarning(
                 new WarningMessage(
                     WarningMessage.POSSIBLE_ERRORS,
                     "Transform Class "
                         + entry.getKey()
                         + " is specified as a global transform in "
                         + entry.getValue().toExternalForm()
                         + " but it is not annotated by "
                         + GroovyASTTransformation.class.getName()
                         + " the global transform associated with it may fail and cause the compilation to fail.",
                     null,
                     null));
         continue;
       }
       if (ASTTransformation.class.isAssignableFrom(gTransClass)) {
         final ASTTransformation instance = (ASTTransformation) gTransClass.newInstance();
         if (instance instanceof CompilationUnitAware) {
           ((CompilationUnitAware) instance).setCompilationUnit(compilationUnit);
         }
         CompilationUnit.SourceUnitOperation suOp =
             new CompilationUnit.SourceUnitOperation() {
               public void call(SourceUnit source) throws CompilationFailedException {
                 instance.visit(new ASTNode[] {source.getAST()}, source);
               }
             };
         if (isFirstScan) {
           compilationUnit.addPhaseOperation(suOp, transformAnnotation.phase().getPhaseNumber());
         } else {
           compilationUnit.addNewPhaseOperation(
               suOp, transformAnnotation.phase().getPhaseNumber());
         }
       } else {
         compilationUnit
             .getErrorCollector()
             .addError(
                 new SimpleMessage(
                     "Transform Class "
                         + entry.getKey()
                         + " specified at "
                         + entry.getValue().toExternalForm()
                         + " is not an ASTTransformation.",
                     null));
       }
     } catch (Exception e) {
       compilationUnit
           .getErrorCollector()
           .addError(
               new SimpleMessage(
                   "Could not instantiate global transform class "
                       + entry.getKey()
                       + " specified at "
                       + entry.getValue().toExternalForm()
                       + "  because of exception "
                       + e.toString(),
                   null));
     }
   }
 }
  private static void doAddGlobalTransforms(
      ASTTransformationsContext context, boolean isFirstScan) {
    final CompilationUnit compilationUnit = context.getCompilationUnit();
    GroovyClassLoader transformLoader = compilationUnit.getTransformLoader();
    Map<String, URL> transformNames = new LinkedHashMap<String, URL>();
    try {
      Enumeration<URL> globalServices =
          transformLoader.getResources(
              "META-INF/services/org.codehaus.groovy.transform.ASTTransformation");
      while (globalServices.hasMoreElements()) {
        URL service = globalServices.nextElement();
        String className;
        BufferedReader svcIn = null;
        try {
          svcIn = new BufferedReader(new InputStreamReader(service.openStream()));
          try {
            className = svcIn.readLine();
          } catch (IOException ioe) {
            compilationUnit
                .getErrorCollector()
                .addError(
                    new SimpleMessage(
                        "IOException reading the service definition at "
                            + service.toExternalForm()
                            + " because of exception "
                            + ioe.toString(),
                        null));
            continue;
          }
          Set<String> disabledGlobalTransforms =
              compilationUnit.getConfiguration().getDisabledGlobalASTTransformations();
          if (disabledGlobalTransforms == null) disabledGlobalTransforms = Collections.emptySet();
          while (className != null) {
            if (!className.startsWith("#") && className.length() > 0) {
              if (!disabledGlobalTransforms.contains(className)) {
                if (transformNames.containsKey(className)) {
                  if (!service.equals(transformNames.get(className))) {
                    compilationUnit
                        .getErrorCollector()
                        .addWarning(
                            WarningMessage.POSSIBLE_ERRORS,
                            "The global transform for class "
                                + className
                                + " is defined in both "
                                + transformNames.get(className).toExternalForm()
                                + " and "
                                + service.toExternalForm()
                                + " - the former definition will be used and the latter ignored.",
                            null,
                            null);
                  }

                } else {
                  transformNames.put(className, service);
                }
              }
            }
            try {
              className = svcIn.readLine();
            } catch (IOException ioe) {
              compilationUnit
                  .getErrorCollector()
                  .addError(
                      new SimpleMessage(
                          "IOException reading the service definition at "
                              + service.toExternalForm()
                              + " because of exception "
                              + ioe.toString(),
                          null));
              //noinspection UnnecessaryContinue
              continue;
            }
          }
        } finally {
          if (svcIn != null) svcIn.close();
        }
      }
    } catch (IOException e) {
      // FIXME the warning message will NPE with what I have :(
      compilationUnit
          .getErrorCollector()
          .addError(
              new SimpleMessage(
                  "IO Exception attempting to load global transforms:" + e.getMessage(), null));
    }
    try {
      Class.forName("java.lang.annotation.Annotation"); // test for 1.5 JVM
    } catch (Exception e) {
      // we failed, notify the user
      StringBuffer sb = new StringBuffer();
      sb.append("Global ASTTransformations are not enabled in retro builds of groovy.\n");
      sb.append("The following transformations will be ignored:");
      for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
        sb.append('\t');
        sb.append(entry.getKey());
        sb.append('\n');
      }
      compilationUnit
          .getErrorCollector()
          .addWarning(
              new WarningMessage(WarningMessage.POSSIBLE_ERRORS, sb.toString(), null, null));
      return;
    }

    // record the transforms found in the first scan, so that in the 2nd scan, phase operations
    // can be added for only for new transforms that have come in
    if (isFirstScan) {
      for (Map.Entry<String, URL> entry : transformNames.entrySet()) {
        context.getGlobalTransformNames().add(entry.getKey());
      }
      addPhaseOperationsForGlobalTransforms(
          context.getCompilationUnit(), transformNames, isFirstScan);
    } else {
      Iterator<Map.Entry<String, URL>> it = transformNames.entrySet().iterator();
      while (it.hasNext()) {
        Map.Entry<String, URL> entry = it.next();
        if (!context.getGlobalTransformNames().add(entry.getKey())) {
          // phase operations for this transform class have already been added before, so remove
          // from current scan cycle
          it.remove();
        }
      }
      addPhaseOperationsForGlobalTransforms(
          context.getCompilationUnit(), transformNames, isFirstScan);
    }
  }