You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/01/27 04:34:14 UTC

[groovy] branch master updated: GROOVY-8971: The VMPlugin configureClassNode method should retain parameter name information when available

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 20c452b  GROOVY-8971: The VMPlugin configureClassNode method should retain parameter name information when available
20c452b is described below

commit 20c452b6804a42aa522359a2754e0cec82e46420
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sun Jan 27 14:33:38 2019 +1000

    GROOVY-8971: The VMPlugin configureClassNode method should retain parameter name information when available
---
 .../org/codehaus/groovy/vmplugin/v5/Java5.java     | 1072 ++++++++++----------
 .../org/codehaus/groovy/vmplugin/v8/Java8.java     |   20 +
 2 files changed, 557 insertions(+), 535 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java b/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
index 61bd2c7..b745405 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v5/Java5.java
@@ -1,535 +1,537 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.vmplugin.v5;
-
-import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.AnnotatedNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.CompileUnit;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.GenericsType;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.PackageNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
-import org.codehaus.groovy.ast.stmt.ReturnStatement;
-import org.codehaus.groovy.vmplugin.VMPlugin;
-import org.codehaus.groovy.vmplugin.VMPluginFactory;
-
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.MalformedParameterizedTypeException;
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.List;
-
-/**
- * java 5 based functions
- *
- * @author Jochen Theodorou
- */
-public class Java5 implements VMPlugin {
-    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
-    private static final Class[] PLUGIN_DGM = {PluginDefaultGroovyMethods.class};
-    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
-    private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
-
-    public void setAdditionalClassInformation(ClassNode cn) {
-        setGenericsTypes(cn);
-    }
-
-    private void setGenericsTypes(ClassNode cn) {
-        TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
-        GenericsType[] gts = configureTypeVariable(tvs);
-        cn.setGenericsTypes(gts);
-    }
-
-    private GenericsType[] configureTypeVariable(TypeVariable[] tvs) {
-        if (tvs.length == 0) return null;
-        GenericsType[] gts = new GenericsType[tvs.length];
-        for (int i = 0; i < tvs.length; i++) {
-            gts[i] = configureTypeVariableDefinition(tvs[i]);
-        }
-        return gts;
-    }
-
-    private GenericsType configureTypeVariableDefinition(TypeVariable tv) {
-        return configureTypeVariableDefinition(configureTypeVariableReference(tv.getName()), configureTypes(tv.getBounds()));
-    }
-
-    public static GenericsType configureTypeVariableDefinition(ClassNode base, ClassNode[] cBounds) {
-        ClassNode redirect = base.redirect();
-        base.setRedirect(null);
-        GenericsType gt;
-        if (cBounds == null || cBounds.length == 0) {
-            gt = new GenericsType(base);
-        } else {
-            gt = new GenericsType(base, cBounds, null);
-            gt.setName(base.getName());
-            gt.setPlaceholder(true);
-        }
-        base.setRedirect(redirect);
-        return gt;
-    }
-
-    private ClassNode[] configureTypes(Type[] types) {
-        if (types.length == 0) return null;
-        ClassNode[] nodes = new ClassNode[types.length];
-        for (int i = 0; i < types.length; i++) {
-            nodes[i] = configureType(types[i]);
-        }
-        return nodes;
-    }
-
-    private ClassNode configureType(Type type) {
-        if (type instanceof WildcardType) {
-            return configureWildcardType((WildcardType) type);
-        } else if (type instanceof ParameterizedType) {
-            return configureParameterizedType((ParameterizedType) type);
-        } else if (type instanceof GenericArrayType) {
-            return configureGenericArray((GenericArrayType) type);
-        } else if (type instanceof TypeVariable) {
-            return configureTypeVariableReference(((TypeVariable) type).getName());
-        } else if (type instanceof Class) {
-            return configureClass((Class) type);
-        } else if (type==null) {
-            throw new GroovyBugError("Type is null. Most probably you let a transform reuse existing ClassNodes with generics information, that is now used in a wrong context.");
-        } else {
-            throw new GroovyBugError("unknown type: " + type + " := " + type.getClass());
-        }
-    }
-
-    private static ClassNode configureClass(Class c) {
-        if (c.isPrimitive()) {
-            return ClassHelper.make(c);
-        } else {
-            return ClassHelper.makeWithoutCaching(c, false);
-        }
-    }
-
-    private ClassNode configureGenericArray(GenericArrayType genericArrayType) {
-        Type component = genericArrayType.getGenericComponentType();
-        ClassNode node = configureType(component);
-        return node.makeArray();
-    }
-
-    private ClassNode configureWildcardType(WildcardType wildcardType) {
-        ClassNode base = ClassHelper.makeWithoutCaching("?");
-        base.setRedirect(ClassHelper.OBJECT_TYPE);
-        //TODO: more than one lower bound for wildcards?
-        ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
-        ClassNode lower = null;
-        // TODO: is it safe to remove this? What was the original intention?
-        if (lowers != null) lower = lowers[0];
-
-        ClassNode[] upper = configureTypes(wildcardType.getUpperBounds());
-        GenericsType t = new GenericsType(base, upper, lower);
-        t.setWildcard(true);
-
-        ClassNode ref = ClassHelper.makeWithoutCaching(Object.class, false);
-        ref.setGenericsTypes(new GenericsType[]{t});
-
-        return ref;
-    }
-
-    private ClassNode configureParameterizedType(ParameterizedType parameterizedType) {
-        ClassNode base = configureType(parameterizedType.getRawType());
-        GenericsType[] gts = configureTypeArguments(parameterizedType.getActualTypeArguments());
-        base.setGenericsTypes(gts);
-        return base;
-    }
-
-    public static ClassNode configureTypeVariableReference(String name) {
-        ClassNode cn = ClassHelper.makeWithoutCaching(name);
-        cn.setGenericsPlaceHolder(true);
-        ClassNode cn2 = ClassHelper.makeWithoutCaching(name);
-        cn2.setGenericsPlaceHolder(true);
-        GenericsType[] gts = new GenericsType[]{new GenericsType(cn2)};
-        cn.setGenericsTypes(gts);
-        cn.setRedirect(ClassHelper.OBJECT_TYPE);
-        return cn;
-    }
-
-    private GenericsType[] configureTypeArguments(Type[] ta) {
-        if (ta.length == 0) return null;
-        GenericsType[] gts = new GenericsType[ta.length];
-        for (int i = 0; i < ta.length; i++) {
-            ClassNode t = configureType(ta[i]);
-            if (ta[i] instanceof WildcardType) {
-                GenericsType[] gen = t.getGenericsTypes();
-                gts[i] = gen[0];
-            } else {
-                gts[i] = new GenericsType(t);
-            }
-        }
-        return gts;
-    }
-
-    public Class[] getPluginDefaultGroovyMethods() {
-        return PLUGIN_DGM;
-    }
-
-    public Class[] getPluginStaticGroovyMethods() {
-        return EMPTY_CLASS_ARRAY;
-    }
-
-    private void setAnnotationMetaData(Annotation[] annotations, AnnotatedNode an) {
-        for (Annotation annotation : annotations) {
-            AnnotationNode node = new AnnotationNode(ClassHelper.make(annotation.annotationType()));
-            configureAnnotation(node, annotation);
-            an.addAnnotation(node);
-        }
-    }
-
-    @Deprecated
-    public void configureAnnotationFromDefinition(AnnotationNode definition, AnnotationNode root) {
-        VMPlugin plugin = VMPluginFactory.getPlugin();
-        plugin.configureAnnotationNodeFromDefinition(definition, root);
-    }
-
-    public void configureAnnotationNodeFromDefinition(AnnotationNode definition, AnnotationNode root) {
-        ClassNode type = definition.getClassNode();
-        if ("java.lang.annotation.Retention".equals(type.getName())) {
-            Expression exp = definition.getMember("value");
-            if (!(exp instanceof PropertyExpression)) return;
-            PropertyExpression pe = (PropertyExpression) exp;
-            String name = pe.getPropertyAsString();
-            RetentionPolicy policy = RetentionPolicy.valueOf(name);
-            setRetentionPolicy(policy, root);
-        } else if ("java.lang.annotation.Target".equals(type.getName())) {
-            Expression exp = definition.getMember("value");
-            if (!(exp instanceof ListExpression)) return;
-            ListExpression le = (ListExpression) exp;
-            int bitmap = 0;
-            for (Expression e : le.getExpressions()) {
-                if (!(e instanceof PropertyExpression)) return;
-                PropertyExpression element = (PropertyExpression) e;
-                String name = element.getPropertyAsString();
-                ElementType value = ElementType.valueOf(name);
-                bitmap |= getElementCode(value);
-            }
-            root.setAllowedTargets(bitmap);
-        }
-    }
-
-    public void configureAnnotation(AnnotationNode node) {
-        ClassNode type = node.getClassNode();
-        VMPlugin plugin = VMPluginFactory.getPlugin();
-        List<AnnotationNode> annotations = type.getAnnotations();
-        for (AnnotationNode an : annotations) {
-            plugin.configureAnnotationNodeFromDefinition(an, node);
-        }
-        plugin.configureAnnotationNodeFromDefinition(node, node);
-    }
-
-    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;
-            try {
-                declaredMethods = type.getDeclaredMethods();
-            } catch (SecurityException se) {
-                declaredMethods = EMPTY_METHOD_ARRAY;
-            }
-            for (Method declaredMethod : declaredMethods) {
-                try {
-                    Object value = declaredMethod.invoke(annotation);
-                    Expression valueExpression = annotationValueToExpression(value);
-                    if (valueExpression == null)
-                        continue;
-                    node.setMember(declaredMethod.getName(), valueExpression);
-                } catch (IllegalAccessException | InvocationTargetException e) {
-                }
-            }
-        }
-    }
-
-    private Expression annotationValueToExpression (Object value) {
-        if (value == null || value instanceof String || value instanceof Number || value instanceof Character || value instanceof Boolean)
-            return new ConstantExpression(value);
-
-        if (value instanceof Class)
-            return new ClassExpression(ClassHelper.makeWithoutCaching((Class)value));
-
-        if (value.getClass().isArray()) {
-            ListExpression elementExprs = new ListExpression();
-            int len = Array.getLength(value);
-            for (int i = 0; i != len; ++i)
-                elementExprs.addExpression(annotationValueToExpression(Array.get(value, i)));
-            return elementExprs;
-        }
-
-        return null;
-    }
-
-    private static void setRetentionPolicy(RetentionPolicy value, AnnotationNode node) {
-        switch (value) {
-            case RUNTIME:
-                node.setRuntimeRetention(true);
-                break;
-            case SOURCE:
-                node.setSourceRetention(true);
-                break;
-            case CLASS:
-                node.setClassRetention(true);
-                break;
-            default:
-                throw new GroovyBugError("unsupported Retention " + value);
-        }
-    }
-
-    protected int getElementCode(ElementType value) {
-        switch (value) {
-            case TYPE:
-                return AnnotationNode.TYPE_TARGET;
-            case CONSTRUCTOR:
-                return AnnotationNode.CONSTRUCTOR_TARGET;
-            case METHOD:
-                return AnnotationNode.METHOD_TARGET;
-            case FIELD:
-                return AnnotationNode.FIELD_TARGET;
-            case PARAMETER:
-                return AnnotationNode.PARAMETER_TARGET;
-            case LOCAL_VARIABLE:
-                return AnnotationNode.LOCAL_VARIABLE_TARGET;
-            case ANNOTATION_TYPE:
-                return AnnotationNode.ANNOTATION_TARGET;
-            case PACKAGE:
-                return AnnotationNode.PACKAGE_TARGET;
-        }
-        if ("MODULE".equals(value.name())) {
-            return AnnotationNode.TYPE_TARGET;
-        } else {
-            throw new GroovyBugError("unsupported Target " + value);
-        }
-    }
-
-    private static void setMethodDefaultValue(MethodNode mn, Method m) {
-        Object defaultValue = m.getDefaultValue();
-        ConstantExpression cExp = ConstantExpression.NULL;
-        if (defaultValue!=null) cExp = new ConstantExpression(defaultValue);
-        mn.setCode(new ReturnStatement(cExp));
-        mn.setAnnotationDefault(true);
-    }
-
-    public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) {
-        try {
-            Class clazz = classNode.getTypeClass();
-            Field[] fields = clazz.getDeclaredFields();
-            for (Field f : fields) {
-                ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType());
-                FieldNode fn = new FieldNode(f.getName(), f.getModifiers(), ret, classNode, null);
-                setAnnotationMetaData(f.getAnnotations(), fn);
-                classNode.addField(fn);
-            }
-            Method[] methods = clazz.getDeclaredMethods();
-            for (Method m : methods) {
-                ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType());
-                Parameter[] params = makeParameters(compileUnit, m.getGenericParameterTypes(), m.getParameterTypes(), m.getParameterAnnotations());
-                ClassNode[] exceptions = makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes());
-                MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null);
-                mn.setSynthetic(m.isSynthetic());
-                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(),
-                        getConstructorParameterAnnotations(ctor)
-                );
-                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);
-            }
-        } catch (NoClassDefFoundError e) {
-            throw new NoClassDefFoundError("Unable to load class "+classNode.toString(false)+" due to missing dependency "+e.getMessage());
-        } catch (MalformedParameterizedTypeException e) {
-            throw new RuntimeException("Unable to configure class node for class "+classNode.toString(false)+" due to malformed parameterized types", e);
-        }
-    }
-
-    /**
-     * Synthetic parameters such as those added for inner class constructors may
-     * not be included in the parameter annotations array. This is the case when
-     * at least one parameter of an inner class constructor has an annotation with
-     * a RUNTIME retention (this occurs for JDK8 and below). This method will
-     * normalize the annotations array so that it contains the same number of
-     * elements as the array returned from {@link Constructor#getParameterTypes()}.
-     *
-     * If adjustment is required, the adjusted array will be prepended with a
-     * zero-length element. If no adjustment is required, the original array
-     * from {@link Constructor#getParameterAnnotations()} will be returned.
-     *
-     * @param constructor the Constructor for which to return parameter annotations
-     * @return array of arrays containing the annotations on the parameters of the given Constructor
-     */
-    private Annotation[][] getConstructorParameterAnnotations(Constructor<?> constructor) {
-        /*
-         * TODO: Remove after JDK9 is the minimum JDK supported
-         *
-         * JDK9+ correctly accounts for the synthetic parameter and when it becomes
-         * the minimum version this method should no longer be required.
-         */
-        int parameterCount = constructor.getParameterTypes().length;
-        Annotation[][] annotations = constructor.getParameterAnnotations();
-        int diff = parameterCount - annotations.length;
-        if (diff > 0) {
-            // May happen on JDK8 and below, but we only expect to have to
-            // add a single element to the front of the array to account
-            // for the synthetic outer reference
-            if (diff > 1) {
-                throw new GroovyBugError(
-                        "Constructor parameter annotations length [" + annotations.length + "] " +
-                        "does not match the parameter length: " + constructor
-                );
-            }
-            Annotation[][] adjusted = new Annotation[parameterCount][];
-            adjusted[0] = EMPTY_ANNOTATION_ARRAY;
-            System.arraycopy(annotations, 0, adjusted, 1, annotations.length);
-            return adjusted;
-        }
-        return annotations;
-    }
-
-    private void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class clazz) {
-        Type[] interfaceTypes = clazz.getGenericInterfaces();
-        if (interfaceTypes.length == 0) {
-            classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
-        } else {
-            ClassNode[] ret = new ClassNode[interfaceTypes.length];
-            for (int i = 0; i < interfaceTypes.length; i++) {
-                Type type = interfaceTypes[i];
-                while (!(type instanceof Class)) {
-                    ParameterizedType pt = (ParameterizedType) type;
-                    Type t2 = pt.getRawType();
-                    if (t2==type) {
-                        throw new GroovyBugError("Cannot transform generic signature of "+clazz+
-                                " with generic interface "+interfaceTypes[i]+" to a class.");
-                    }
-                    type = t2;
-                }
-                ret[i] = makeClassNode(cu, interfaceTypes[i], (Class) type);
-            }
-            classNode.setInterfaces(ret);
-        }
-    }
-
-    private ClassNode[] makeClassNodes(CompileUnit cu, Type[] types, Class[] cls) {
-        ClassNode[] nodes = new ClassNode[types.length];
-        for (int i = 0; i < nodes.length; i++) {
-            nodes[i] = makeClassNode(cu, types[i], cls[i]);
-        }
-        return nodes;
-    }
-
-    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.getPlainNodeReference();
-    }
-
-    private Parameter[] makeParameters(CompileUnit cu, Type[] types, Class[] cls, Annotation[][] parameterAnnotations) {
-        Parameter[] params = Parameter.EMPTY_ARRAY;
-        if (types.length > 0) {
-            params = new Parameter[types.length];
-            for (int i = 0; i < params.length; i++) {
-                params[i] = makeParameter(cu, types[i], cls[i], parameterAnnotations[i], i);
-            }
-        }
-        return params;
-    }
-
-    private Parameter makeParameter(CompileUnit cu, Type type, Class cl, Annotation[] annotations, int idx) {
-        ClassNode cn = makeClassNode(cu, type, cl);
-        Parameter parameter = new Parameter(cn, "param" + idx);
-        setAnnotationMetaData(annotations, parameter);
-        return parameter;
-    }
-
-    public void invalidateCallSites() {}
-
-    @Override
-    public Object getInvokeSpecialHandle(Method m, Object receiver){
-        throw new GroovyBugError("getInvokeSpecialHandle requires at least JDK 7 wot private access to Lookup");
-    }
-
-    @Override
-    public int getVersion() {
-        return 5;
-    }
-
-    @Override
-    public Object invokeHandle(Object handle, Object[] args) throws Throwable {
-        throw new GroovyBugError("invokeHandle requires at least JDK 7");
-    }
-}
-
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.vmplugin.v5;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.MalformedParameterizedTypeException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+/**
+ * java 5 based functions
+ */
+public class Java5 implements VMPlugin {
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+    private static final Class[] PLUGIN_DGM = {PluginDefaultGroovyMethods.class};
+    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
+    private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
+
+    public void setAdditionalClassInformation(ClassNode cn) {
+        setGenericsTypes(cn);
+    }
+
+    private void setGenericsTypes(ClassNode cn) {
+        TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
+        GenericsType[] gts = configureTypeVariable(tvs);
+        cn.setGenericsTypes(gts);
+    }
+
+    private GenericsType[] configureTypeVariable(TypeVariable[] tvs) {
+        if (tvs.length == 0) return null;
+        GenericsType[] gts = new GenericsType[tvs.length];
+        for (int i = 0; i < tvs.length; i++) {
+            gts[i] = configureTypeVariableDefinition(tvs[i]);
+        }
+        return gts;
+    }
+
+    private GenericsType configureTypeVariableDefinition(TypeVariable tv) {
+        return configureTypeVariableDefinition(configureTypeVariableReference(tv.getName()), configureTypes(tv.getBounds()));
+    }
+
+    public static GenericsType configureTypeVariableDefinition(ClassNode base, ClassNode[] cBounds) {
+        ClassNode redirect = base.redirect();
+        base.setRedirect(null);
+        GenericsType gt;
+        if (cBounds == null || cBounds.length == 0) {
+            gt = new GenericsType(base);
+        } else {
+            gt = new GenericsType(base, cBounds, null);
+            gt.setName(base.getName());
+            gt.setPlaceholder(true);
+        }
+        base.setRedirect(redirect);
+        return gt;
+    }
+
+    private ClassNode[] configureTypes(Type[] types) {
+        if (types.length == 0) return null;
+        ClassNode[] nodes = new ClassNode[types.length];
+        for (int i = 0; i < types.length; i++) {
+            nodes[i] = configureType(types[i]);
+        }
+        return nodes;
+    }
+
+    private ClassNode configureType(Type type) {
+        if (type instanceof WildcardType) {
+            return configureWildcardType((WildcardType) type);
+        } else if (type instanceof ParameterizedType) {
+            return configureParameterizedType((ParameterizedType) type);
+        } else if (type instanceof GenericArrayType) {
+            return configureGenericArray((GenericArrayType) type);
+        } else if (type instanceof TypeVariable) {
+            return configureTypeVariableReference(((TypeVariable) type).getName());
+        } else if (type instanceof Class) {
+            return configureClass((Class) type);
+        } else if (type==null) {
+            throw new GroovyBugError("Type is null. Most probably you let a transform reuse existing ClassNodes with generics information, that is now used in a wrong context.");
+        } else {
+            throw new GroovyBugError("unknown type: " + type + " := " + type.getClass());
+        }
+    }
+
+    private static ClassNode configureClass(Class c) {
+        if (c.isPrimitive()) {
+            return ClassHelper.make(c);
+        } else {
+            return ClassHelper.makeWithoutCaching(c, false);
+        }
+    }
+
+    private ClassNode configureGenericArray(GenericArrayType genericArrayType) {
+        Type component = genericArrayType.getGenericComponentType();
+        ClassNode node = configureType(component);
+        return node.makeArray();
+    }
+
+    private ClassNode configureWildcardType(WildcardType wildcardType) {
+        ClassNode base = ClassHelper.makeWithoutCaching("?");
+        base.setRedirect(ClassHelper.OBJECT_TYPE);
+        //TODO: more than one lower bound for wildcards?
+        ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
+        ClassNode lower = null;
+        // TODO: is it safe to remove this? What was the original intention?
+        if (lowers != null) lower = lowers[0];
+
+        ClassNode[] upper = configureTypes(wildcardType.getUpperBounds());
+        GenericsType t = new GenericsType(base, upper, lower);
+        t.setWildcard(true);
+
+        ClassNode ref = ClassHelper.makeWithoutCaching(Object.class, false);
+        ref.setGenericsTypes(new GenericsType[]{t});
+
+        return ref;
+    }
+
+    private ClassNode configureParameterizedType(ParameterizedType parameterizedType) {
+        ClassNode base = configureType(parameterizedType.getRawType());
+        GenericsType[] gts = configureTypeArguments(parameterizedType.getActualTypeArguments());
+        base.setGenericsTypes(gts);
+        return base;
+    }
+
+    public static ClassNode configureTypeVariableReference(String name) {
+        ClassNode cn = ClassHelper.makeWithoutCaching(name);
+        cn.setGenericsPlaceHolder(true);
+        ClassNode cn2 = ClassHelper.makeWithoutCaching(name);
+        cn2.setGenericsPlaceHolder(true);
+        GenericsType[] gts = new GenericsType[]{new GenericsType(cn2)};
+        cn.setGenericsTypes(gts);
+        cn.setRedirect(ClassHelper.OBJECT_TYPE);
+        return cn;
+    }
+
+    private GenericsType[] configureTypeArguments(Type[] ta) {
+        if (ta.length == 0) return null;
+        GenericsType[] gts = new GenericsType[ta.length];
+        for (int i = 0; i < ta.length; i++) {
+            ClassNode t = configureType(ta[i]);
+            if (ta[i] instanceof WildcardType) {
+                GenericsType[] gen = t.getGenericsTypes();
+                gts[i] = gen[0];
+            } else {
+                gts[i] = new GenericsType(t);
+            }
+        }
+        return gts;
+    }
+
+    public Class[] getPluginDefaultGroovyMethods() {
+        return PLUGIN_DGM;
+    }
+
+    public Class[] getPluginStaticGroovyMethods() {
+        return EMPTY_CLASS_ARRAY;
+    }
+
+    private void setAnnotationMetaData(Annotation[] annotations, AnnotatedNode an) {
+        for (Annotation annotation : annotations) {
+            AnnotationNode node = new AnnotationNode(ClassHelper.make(annotation.annotationType()));
+            configureAnnotation(node, annotation);
+            an.addAnnotation(node);
+        }
+    }
+
+    @Deprecated
+    public void configureAnnotationFromDefinition(AnnotationNode definition, AnnotationNode root) {
+        VMPlugin plugin = VMPluginFactory.getPlugin();
+        plugin.configureAnnotationNodeFromDefinition(definition, root);
+    }
+
+    public void configureAnnotationNodeFromDefinition(AnnotationNode definition, AnnotationNode root) {
+        ClassNode type = definition.getClassNode();
+        if ("java.lang.annotation.Retention".equals(type.getName())) {
+            Expression exp = definition.getMember("value");
+            if (!(exp instanceof PropertyExpression)) return;
+            PropertyExpression pe = (PropertyExpression) exp;
+            String name = pe.getPropertyAsString();
+            RetentionPolicy policy = RetentionPolicy.valueOf(name);
+            setRetentionPolicy(policy, root);
+        } else if ("java.lang.annotation.Target".equals(type.getName())) {
+            Expression exp = definition.getMember("value");
+            if (!(exp instanceof ListExpression)) return;
+            ListExpression le = (ListExpression) exp;
+            int bitmap = 0;
+            for (Expression e : le.getExpressions()) {
+                if (!(e instanceof PropertyExpression)) return;
+                PropertyExpression element = (PropertyExpression) e;
+                String name = element.getPropertyAsString();
+                ElementType value = ElementType.valueOf(name);
+                bitmap |= getElementCode(value);
+            }
+            root.setAllowedTargets(bitmap);
+        }
+    }
+
+    public void configureAnnotation(AnnotationNode node) {
+        ClassNode type = node.getClassNode();
+        VMPlugin plugin = VMPluginFactory.getPlugin();
+        List<AnnotationNode> annotations = type.getAnnotations();
+        for (AnnotationNode an : annotations) {
+            plugin.configureAnnotationNodeFromDefinition(an, node);
+        }
+        plugin.configureAnnotationNodeFromDefinition(node, node);
+    }
+
+    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;
+            try {
+                declaredMethods = type.getDeclaredMethods();
+            } catch (SecurityException se) {
+                declaredMethods = EMPTY_METHOD_ARRAY;
+            }
+            for (Method declaredMethod : declaredMethods) {
+                try {
+                    Object value = declaredMethod.invoke(annotation);
+                    Expression valueExpression = annotationValueToExpression(value);
+                    if (valueExpression == null)
+                        continue;
+                    node.setMember(declaredMethod.getName(), valueExpression);
+                } catch (IllegalAccessException | InvocationTargetException e) {
+                }
+            }
+        }
+    }
+
+    private Expression annotationValueToExpression (Object value) {
+        if (value == null || value instanceof String || value instanceof Number || value instanceof Character || value instanceof Boolean)
+            return new ConstantExpression(value);
+
+        if (value instanceof Class)
+            return new ClassExpression(ClassHelper.makeWithoutCaching((Class)value));
+
+        if (value.getClass().isArray()) {
+            ListExpression elementExprs = new ListExpression();
+            int len = Array.getLength(value);
+            for (int i = 0; i != len; ++i)
+                elementExprs.addExpression(annotationValueToExpression(Array.get(value, i)));
+            return elementExprs;
+        }
+
+        return null;
+    }
+
+    private static void setRetentionPolicy(RetentionPolicy value, AnnotationNode node) {
+        switch (value) {
+            case RUNTIME:
+                node.setRuntimeRetention(true);
+                break;
+            case SOURCE:
+                node.setSourceRetention(true);
+                break;
+            case CLASS:
+                node.setClassRetention(true);
+                break;
+            default:
+                throw new GroovyBugError("unsupported Retention " + value);
+        }
+    }
+
+    protected int getElementCode(ElementType value) {
+        switch (value) {
+            case TYPE:
+                return AnnotationNode.TYPE_TARGET;
+            case CONSTRUCTOR:
+                return AnnotationNode.CONSTRUCTOR_TARGET;
+            case METHOD:
+                return AnnotationNode.METHOD_TARGET;
+            case FIELD:
+                return AnnotationNode.FIELD_TARGET;
+            case PARAMETER:
+                return AnnotationNode.PARAMETER_TARGET;
+            case LOCAL_VARIABLE:
+                return AnnotationNode.LOCAL_VARIABLE_TARGET;
+            case ANNOTATION_TYPE:
+                return AnnotationNode.ANNOTATION_TARGET;
+            case PACKAGE:
+                return AnnotationNode.PACKAGE_TARGET;
+        }
+        if ("MODULE".equals(value.name())) {
+            return AnnotationNode.TYPE_TARGET;
+        } else {
+            throw new GroovyBugError("unsupported Target " + value);
+        }
+    }
+
+    private static void setMethodDefaultValue(MethodNode mn, Method m) {
+        Object defaultValue = m.getDefaultValue();
+        ConstantExpression cExp = ConstantExpression.NULL;
+        if (defaultValue!=null) cExp = new ConstantExpression(defaultValue);
+        mn.setCode(new ReturnStatement(cExp));
+        mn.setAnnotationDefault(true);
+    }
+
+    public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) {
+        try {
+            Class clazz = classNode.getTypeClass();
+            Field[] fields = clazz.getDeclaredFields();
+            for (Field f : fields) {
+                ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType());
+                FieldNode fn = new FieldNode(f.getName(), f.getModifiers(), ret, classNode, null);
+                setAnnotationMetaData(f.getAnnotations(), fn);
+                classNode.addField(fn);
+            }
+            Method[] methods = clazz.getDeclaredMethods();
+            for (Method m : methods) {
+                ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType());
+                Parameter[] params = processParameters(compileUnit, m);
+                ClassNode[] exceptions = makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes());
+                MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null);
+                mn.setSynthetic(m.isSynthetic());
+                setMethodDefaultValue(mn, m);
+                setAnnotationMetaData(m.getAnnotations(), mn);
+                mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
+                classNode.addMethod(mn);
+            }
+            Constructor[] constructors = clazz.getDeclaredConstructors();
+            for (Constructor ctor : constructors) {
+                Type[] types = ctor.getGenericParameterTypes();
+                Parameter[] params1 = Parameter.EMPTY_ARRAY;
+                if (types.length > 0) {
+                    params1 = new Parameter[types.length];
+                    for (int i = 0; i < params1.length; i++) {
+                        params1[i] = makeParameter(compileUnit, types[i], ctor.getParameterTypes()[i], getConstructorParameterAnnotations(ctor)[i], "param" + i);
+                    }
+                }
+                Parameter[] params = params1;
+                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);
+            }
+        } catch (NoClassDefFoundError e) {
+            throw new NoClassDefFoundError("Unable to load class "+classNode.toString(false)+" due to missing dependency "+e.getMessage());
+        } catch (MalformedParameterizedTypeException e) {
+            throw new RuntimeException("Unable to configure class node for class "+classNode.toString(false)+" due to malformed parameterized types", e);
+        }
+    }
+
+    protected Parameter[] processParameters(CompileUnit compileUnit, Method m) {
+        Type[] types = m.getGenericParameterTypes();
+        Parameter[] params = Parameter.EMPTY_ARRAY;
+        if (types.length > 0) {
+            params = new Parameter[types.length];
+            for (int i = 0; i < params.length; i++) {
+                params[i] = makeParameter(compileUnit, types[i], m.getParameterTypes()[i], m.getParameterAnnotations()[i], "param" + i);
+            }
+        }
+        return params;
+    }
+
+    /**
+     * Synthetic parameters such as those added for inner class constructors may
+     * not be included in the parameter annotations array. This is the case when
+     * at least one parameter of an inner class constructor has an annotation with
+     * a RUNTIME retention (this occurs for JDK8 and below). This method will
+     * normalize the annotations array so that it contains the same number of
+     * elements as the array returned from {@link Constructor#getParameterTypes()}.
+     *
+     * If adjustment is required, the adjusted array will be prepended with a
+     * zero-length element. If no adjustment is required, the original array
+     * from {@link Constructor#getParameterAnnotations()} will be returned.
+     *
+     * @param constructor the Constructor for which to return parameter annotations
+     * @return array of arrays containing the annotations on the parameters of the given Constructor
+     */
+    private Annotation[][] getConstructorParameterAnnotations(Constructor<?> constructor) {
+        /*
+         * TODO: Remove after JDK9 is the minimum JDK supported
+         *
+         * JDK9+ correctly accounts for the synthetic parameter and when it becomes
+         * the minimum version this method should no longer be required.
+         */
+        int parameterCount = constructor.getParameterTypes().length;
+        Annotation[][] annotations = constructor.getParameterAnnotations();
+        int diff = parameterCount - annotations.length;
+        if (diff > 0) {
+            // May happen on JDK8 and below, but we only expect to have to
+            // add a single element to the front of the array to account
+            // for the synthetic outer reference
+            if (diff > 1) {
+                throw new GroovyBugError(
+                        "Constructor parameter annotations length [" + annotations.length + "] " +
+                        "does not match the parameter length: " + constructor
+                );
+            }
+            Annotation[][] adjusted = new Annotation[parameterCount][];
+            adjusted[0] = EMPTY_ANNOTATION_ARRAY;
+            System.arraycopy(annotations, 0, adjusted, 1, annotations.length);
+            return adjusted;
+        }
+        return annotations;
+    }
+
+    private void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class clazz) {
+        Type[] interfaceTypes = clazz.getGenericInterfaces();
+        if (interfaceTypes.length == 0) {
+            classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
+        } else {
+            ClassNode[] ret = new ClassNode[interfaceTypes.length];
+            for (int i = 0; i < interfaceTypes.length; i++) {
+                Type type = interfaceTypes[i];
+                while (!(type instanceof Class)) {
+                    ParameterizedType pt = (ParameterizedType) type;
+                    Type t2 = pt.getRawType();
+                    if (t2==type) {
+                        throw new GroovyBugError("Cannot transform generic signature of "+clazz+
+                                " with generic interface "+interfaceTypes[i]+" to a class.");
+                    }
+                    type = t2;
+                }
+                ret[i] = makeClassNode(cu, interfaceTypes[i], (Class) type);
+            }
+            classNode.setInterfaces(ret);
+        }
+    }
+
+    private ClassNode[] makeClassNodes(CompileUnit cu, Type[] types, Class[] cls) {
+        ClassNode[] nodes = new ClassNode[types.length];
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = makeClassNode(cu, types[i], cls[i]);
+        }
+        return nodes;
+    }
+
+    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.getPlainNodeReference();
+    }
+
+    protected Parameter makeParameter(CompileUnit cu, Type type, Class cl, Annotation[] annotations, String name) {
+        ClassNode cn = makeClassNode(cu, type, cl);
+        Parameter parameter = new Parameter(cn, name);
+        setAnnotationMetaData(annotations, parameter);
+        return parameter;
+    }
+
+    public void invalidateCallSites() {}
+
+    @Override
+    public Object getInvokeSpecialHandle(Method m, Object receiver){
+        throw new GroovyBugError("getInvokeSpecialHandle requires at least JDK 7 wot private access to Lookup");
+    }
+
+    @Override
+    public int getVersion() {
+        return 5;
+    }
+
+    @Override
+    public Object invokeHandle(Object handle, Object[] args) throws Throwable {
+        throw new GroovyBugError("invokeHandle requires at least JDK 7");
+    }
+}
+
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
index 3a659b7..f4bd201 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
@@ -19,9 +19,13 @@
 package org.codehaus.groovy.vmplugin.v8;
 
 import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.vmplugin.v7.Java7;
 
 import java.lang.annotation.ElementType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -63,4 +67,20 @@ public class Java8 extends Java7 {
         }
         return super.getElementCode(value);
     }
+
+    @Override
+    protected Parameter[] processParameters(CompileUnit compileUnit, Method m) {
+        java.lang.reflect.Parameter[] parameters = m.getParameters();
+        Type[] types = m.getGenericParameterTypes();
+        Parameter[] params = Parameter.EMPTY_ARRAY;
+        if (types.length > 0) {
+            params = new Parameter[types.length];
+            for (int i = 0; i < params.length; i++) {
+                java.lang.reflect.Parameter p = parameters[i];
+                String name = p.isNamePresent() ? p.getName() : "param" + i;
+                params[i] = makeParameter(compileUnit, types[i], m.getParameterTypes()[i], m.getParameterAnnotations()[i], name);
+            }
+        }
+        return params;
+    }
 }