private Statement createConstructorStatement( ClassNode cNode, PropertyNode pNode, List<String> knownImmutableClasses, List<String> knownImmutables) { FieldNode fNode = pNode.getField(); final ClassNode fieldType = fNode.getType(); Statement statement = null; if (fieldType.isArray() || isOrImplements(fieldType, CLONEABLE_TYPE)) { statement = createConstructorStatementArrayOrCloneable(fNode); } else if (isKnownImmutableClass(fieldType, knownImmutableClasses) || isKnownImmutable(pNode.getName(), knownImmutables)) { statement = createConstructorStatementDefault(fNode); } else if (fieldType.isDerivedFrom(DATE_TYPE)) { statement = createConstructorStatementDate(fNode); } else if (isOrImplements(fieldType, COLLECTION_TYPE) || fieldType.isDerivedFrom(COLLECTION_TYPE) || isOrImplements(fieldType, MAP_TYPE) || fieldType.isDerivedFrom(MAP_TYPE)) { statement = createConstructorStatementCollection(fNode); } else if (fieldType.isResolved()) { addError( createErrorMessage(cNode.getName(), fNode.getName(), fieldType.getName(), "compiling"), fNode); statement = EmptyStatement.INSTANCE; } else { statement = createConstructorStatementGuarded(cNode, fNode); } return statement; }
private void printTypeName(PrintWriter out, ClassNode type) { if (ClassHelper.isPrimitiveType(type)) { if (type == ClassHelper.boolean_TYPE) { out.print("boolean"); } else if (type == ClassHelper.char_TYPE) { out.print("char"); } else if (type == ClassHelper.int_TYPE) { out.print("int"); } else if (type == ClassHelper.short_TYPE) { out.print("short"); } else if (type == ClassHelper.long_TYPE) { out.print("long"); } else if (type == ClassHelper.float_TYPE) { out.print("float"); } else if (type == ClassHelper.double_TYPE) { out.print("double"); } else if (type == ClassHelper.byte_TYPE) { out.print("byte"); } else { out.print("void"); } } else { String name = type.getName(); // check for an alias ClassNode alias = currentModule.getImportType(name); if (alias != null) name = alias.getName(); out.print(name.replace('$', '.')); } }
public static void configureAnnotationFromDefinition( 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); } }
private String genericsBounds(ClassNode theType, Set<String> visited) { String ret = theType.isArray() ? theType.getComponentType().getName() + "[]" : theType.getName(); GenericsType[] genericsTypes = theType.getGenericsTypes(); if (genericsTypes == null || genericsTypes.length == 0) return ret; // TODO instead of catching Object<T> here stop it from being placed into type in first place if (genericsTypes.length == 1 && genericsTypes[0].isPlaceholder() && theType.getName().equals("java.lang.Object")) { return genericsTypes[0].getName(); } ret += "<"; for (int i = 0; i < genericsTypes.length; i++) { if (i != 0) ret += ", "; GenericsType type = genericsTypes[i]; if (type.isPlaceholder() && visited.contains(type.getName())) { ret += type.getName(); } else { ret += type.toString(visited); } } ret += ">"; return ret; }
private boolean isKnownImmutableClass(ClassNode fieldType, List<String> knownImmutableClasses) { if (!fieldType.isResolved()) return false; return fieldType.isEnum() || ClassHelper.isPrimitiveType(fieldType) || fieldType.getAnnotations(MY_TYPE).size() != 0 || inImmutableList(fieldType.getName()) || knownImmutableClasses.contains(fieldType.getName()); }
/** * Lookup a ClassNode by its name from the source unit * * @param type the name of the class whose ClassNode we want to lookup * @return a ClassNode representing the class */ public ClassNode lookupClassNodeFor(String type) { for (ClassNode cn : typeCheckingVisitor.getSourceUnit().getAST().getClasses()) { if (cn.getName().equals(type)) return cn; } return null; }
public void call(SourceUnit source) throws CompilationFailedException { List<ClassNode> classes = source.ast.getClasses(); for (ClassNode node : classes) { CompileUnit cu = node.getCompileUnit(); for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext(); ) { String name = (String) iter.next(); SourceUnit su = ast.getScriptSourceLocation(name); List<ClassNode> classesInSourceUnit = su.ast.getClasses(); StringBuffer message = new StringBuffer(); message .append("Compilation incomplete: expected to find the class ") .append(name) .append(" in ") .append(su.getName()); if (classesInSourceUnit.isEmpty()) { message.append(", but the file seems not to contain any classes"); } else { message.append(", but the file contains the classes: "); boolean first = true; for (ClassNode cn : classesInSourceUnit) { if (!first) { message.append(", "); } else { first = false; } message.append(cn.getName()); } } getErrorCollector() .addErrorAndContinue(new SimpleMessage(message.toString(), CompilationUnit.this)); iter.remove(); } } }
public static String getClassInternalName(ClassNode t) { if (t.isPrimaryClassNode()) { if (t.isArray()) return "[L" + getClassInternalName(t.getComponentType()) + ";"; return getClassInternalName(t.getName()); } return getClassInternalName(t.getTypeClass()); }
/** * Main entry point for the calling the TestForTransformation programmatically. * * @param classNode The class node that represents th test * @param ce The class expression that represents the class to test */ public void testFor(ClassNode classNode, ClassExpression ce) { boolean junit3Test = isJunit3Test(classNode); // make sure the 'log' property is not the one from GroovyTestCase FieldNode log = classNode.getField("log"); if (log == null || log.getDeclaringClass().equals(GROOVY_TEST_CASE_CLASS)) { LoggingTransformer.addLogField(classNode, classNode.getName()); } boolean isSpockTest = isSpockTest(classNode); if (!isSpockTest && !junit3Test) { // assume JUnit 4 Map<String, MethodNode> declaredMethodsMap = classNode.getDeclaredMethodsMap(); for (String methodName : declaredMethodsMap.keySet()) { MethodNode methodNode = declaredMethodsMap.get(methodName); if (isCandidateMethod(methodNode) && methodNode.getName().startsWith("test")) { if (methodNode.getAnnotations().size() == 0) { methodNode.addAnnotation(TEST_ANNOTATION); } } } } final MethodNode methodToAdd = weaveMock(classNode, ce, true); if (methodToAdd != null && junit3Test) { addMethodCallsToMethod(classNode, SET_UP_METHOD, Arrays.asList(methodToAdd)); } }
protected MethodNode weaveMock( ClassNode classNode, ClassExpression value, boolean isClassUnderTest) { ClassNode testTarget = value.getType(); String className = testTarget.getName(); MethodNode testForMethod = null; for (String artefactType : artefactTypeToTestMap.keySet()) { if (className.endsWith(artefactType)) { Class mixinClass = artefactTypeToTestMap.get(artefactType); if (!isAlreadyWoven(classNode, mixinClass)) { weaveMixinClass(classNode, mixinClass); if (isClassUnderTest) { testForMethod = addClassUnderTestMethod(classNode, value, artefactType); } else { addMockCollaboratorToSetup(classNode, value, artefactType); } return testForMethod; } addMockCollaboratorToSetup(classNode, value, artefactType); return null; } } // must be a domain class weaveMixinClass(classNode, DomainClassUnitTestMixin.class); if (isClassUnderTest) { testForMethod = addClassUnderTestMethod(classNode, value, DOMAIN_TYPE); } else { addMockCollaboratorToSetup(classNode, value, DOMAIN_TYPE); } return testForMethod; }
/** * Snoops through the declaring class and all parents looking for methods * * <ul> * <li><code>public String getMessage(java.lang.String)</code> * <li><code>public String getMessage(java.lang.String, java.util.Locale)</code> * <li><code>public String getMessage(java.lang.String, java.lang.Object[])</code> * <li><code>public String getMessage(java.lang.String, java.lang.Object[], java.util.Locale) * </code> * <li><code>public String getMessage(java.lang.String, java.util.List)</code> * <li><code>public String getMessage(java.lang.String, java.util.List, java.util.Locale)</code> * <li><code>public String getMessage(java.lang.String, java.util.Map)</code> * <li><code>public String getMessage(java.lang.String, java.util.Map, java.util.Locale)</code> * <li><code>public String getMessage(java.lang.String, java.lang.String)</code> * <li><code>public String getMessage(java.lang.String, java.lang.String, java.util.Locale) * </code> * <li><code>public String getMessage(java.lang.String, java.lang.Object[], java.lang.String) * </code> * <li><code> * public String getMessage(java.lang.String, java.lang.Object[], java.lang.String, java.util.Locale) * </code> * <li><code>public String getMessage(java.lang.String, java.util.List, java.lang.String)</code> * <li><code> * public String getMessage(java.lang.String, java.util.List, java.lang.String, java.util.Locale) * </code> * <li><code>public String getMessage(java.lang.String, java.util.Map, java.lang.String)</code> * <li><code> * public String getMessage(java.lang.String, java.util.Map, java.lang.String, java.util.Locale) * </code> * </ul> * * If any are defined all must be defined or a compilation error results. * * @param declaringClass the class to search * @param sourceUnit the source unit, for error reporting. {@code @NotNull}. * @return true if property change support should be added */ protected static boolean needsMessageSource(ClassNode declaringClass, SourceUnit sourceUnit) { boolean found = false; ClassNode consideredClass = declaringClass; while (consideredClass != null) { for (MethodNode method : consideredClass.getMethods()) { // just check length, MOP will match it up found = method.getName().equals(METHOD_GET_MESSAGE) && method.getParameters().length == 1; found |= method.getName().equals(METHOD_GET_MESSAGE) && method.getParameters().length == 2; found |= method.getName().equals(METHOD_GET_MESSAGE) && method.getParameters().length == 3; found |= method.getName().equals(METHOD_GET_MESSAGE) && method.getParameters().length == 4; if (found) return false; } consideredClass = consideredClass.getSuperClass(); } if (found) { sourceUnit .getErrorCollector() .addErrorAndContinue( new SimpleMessage( "@MessageSourceAware cannot be processed on " + declaringClass.getName() + " because some but not all of variants of getMessage() were declared in the current class or super classes.", sourceUnit)); return false; } return true; }
/** * Compile the specified Groovy source files, applying any {@link CompilerAutoConfiguration}s. All * classes defined in the files will be returned from this method. * * @param file the file to compile * @return compiled classes * @throws CompilationFailedException * @throws IOException */ public Class<?>[] compile(File... file) throws CompilationFailedException, IOException { this.loader.clearCache(); List<Class<?>> classes = new ArrayList<Class<?>>(); CompilerConfiguration configuration = this.loader.getConfiguration(); CompilationUnit compilationUnit = new CompilationUnit(configuration, null, this.loader); SourceUnit sourceUnit = new SourceUnit(file[0], configuration, this.loader, compilationUnit.getErrorCollector()); ClassCollector collector = this.loader.createCollector(compilationUnit, sourceUnit); compilationUnit.setClassgenCallback(collector); compilationUnit.addSources(file); addAstTransformations(compilationUnit); compilationUnit.compile(Phases.CLASS_GENERATION); for (Object loadedClass : collector.getLoadedClasses()) { classes.add((Class<?>) loadedClass); } ClassNode mainClassNode = (ClassNode) compilationUnit.getAST().getClasses().get(0); Class<?> mainClass = null; for (Class<?> loadedClass : classes) { if (mainClassNode.getName().equals(loadedClass.getName())) { mainClass = loadedClass; } } if (mainClass != null) { classes.remove(mainClass); classes.add(0, mainClass); } return classes.toArray(new Class<?>[classes.size()]); }
public static void addResourceLocatorIfNeeded(SourceUnit source, ClassNode classNode) { if (needsMessageSource(classNode, source)) { if (LOG.isDebugEnabled()) { LOG.debug("Injecting " + ResourceLocator.class.getName() + " into " + classNode.getName()); } apply(classNode); } }
public GenericsType(ClassNode type, ClassNode[] upperBounds, ClassNode lowerBound) { this.type = type; this.name = type.isGenericsPlaceHolder() ? type.getUnresolvedName() : type.getName(); this.upperBounds = upperBounds; this.lowerBound = lowerBound; placeholder = type.isGenericsPlaceHolder(); resolved = false; }
/** * Given a wrapped number type (Byte, Integer, Short, ...), generates bytecode to convert it to a * primitive number (int, long, double) using calls to wrapped.[targetType]Value() * * @param mv method visitor * @param sourceType the wrapped number type * @param targetType the primitive target type */ public static void doCastToPrimitive( MethodVisitor mv, ClassNode sourceType, ClassNode targetType) { mv.visitMethodInsn( INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(sourceType), targetType.getName() + "Value", "()" + BytecodeHelper.getTypeDescription(targetType)); }
public static void addMapConstructors(ClassNode enumClass, boolean hasNoArg) { TupleConstructorASTTransformation.addMapConstructors( enumClass, hasNoArg, "One of the enum constants for enum " + enumClass.getName() + " was initialized with null. Please use a non-null value or define your own constructor."); }
private void visitClassNode(ClassNode cNode, List<PackageScopeTarget> value) { String cName = cNode.getName(); if (cNode.isInterface() && value.size() != 1 && value.get(0) != PackageScopeTarget.CLASS) { throw new RuntimeException( "Error processing interface '" + cName + "'. " + MY_TYPE_NAME + " not allowed for interfaces except when targeting Class level."); } if (value.contains(groovy.transform.PackageScopeTarget.CLASS)) { if (cNode.isSyntheticPublic()) revertVisibility(cNode); else throw new RuntimeException( "Can't use " + MY_TYPE_NAME + " for class '" + cNode.getName() + "' which has explicit visibility."); } if (value.contains(groovy.transform.PackageScopeTarget.METHODS)) { final List<MethodNode> mList = cNode.getMethods(); for (MethodNode mNode : mList) { if (mNode.isSyntheticPublic()) revertVisibility(mNode); } } if (value.contains(PackageScopeTarget.FIELDS)) { final List<PropertyNode> pList = cNode.getProperties(); List<PropertyNode> foundProps = new ArrayList<PropertyNode>(); List<String> foundNames = new ArrayList<String>(); for (PropertyNode pNode : pList) { foundProps.add(pNode); foundNames.add(pNode.getName()); } for (PropertyNode pNode : foundProps) { pList.remove(pNode); } final List<FieldNode> fList = cNode.getFields(); for (FieldNode fNode : fList) { if (foundNames.contains(fNode.getName())) { revertVisibility(fNode); } } } }
public static void addEventPublisherIfNeeded( SourceUnit source, AnnotationNode annotationNode, ClassNode classNode) { if (needsDelegate(classNode, source, METHODS, "EventPublisher", EVENT_PUBLISHER_TYPE)) { LOG.debug("Injecting {} into {}", EVENT_PUBLISHER_TYPE, classNode.getName()); ConstantExpression value = (ConstantExpression) annotationNode.getMember("value"); String beanName = value != null ? value.getText() : null; beanName = isBlank(beanName) ? null : beanName; apply(classNode, beanName); } }
public static void addMessageSourceIfNeeded( SourceUnit source, AnnotationNode annotationNode, ClassNode classNode) { if (needsDelegate(classNode, source, METHODS, "MessageSourceAware", MESSAGE_SOURCE_TYPE)) { LOG.debug("Injecting {} into {}", MESSAGE_SOURCE_TYPE, classNode.getName()); ConstantExpression value = (ConstantExpression) annotationNode.getMember("value"); String beanName = value != null ? value.getText() : null; beanName = isBlank(beanName) ? "applicationMessageSource" : beanName; apply(classNode, beanName); } }
private void printReturn(PrintWriter out, ClassNode retType) { String retName = retType.getName(); if (!retName.equals("void")) { out.print("return "); printDefaultValue(out, retType); out.print(";"); } }
private FieldNode getKeyField(ClassNode target) { List<FieldNode> annotatedFields = getAnnotatedFieldsOfHierarchy(target, KEY_ANNOTATION); if (annotatedFields.isEmpty()) return null; if (annotatedFields.size() > 1) { addCompileError( String.format( "Found more than one key fields, only one is allowed in hierarchy (%s, %s)", getQualifiedName(annotatedFields.get(0)), getQualifiedName(annotatedFields.get(1))), annotatedFields.get(0)); return null; } FieldNode result = annotatedFields.get(0); if (!result.getType().equals(ClassHelper.STRING_TYPE)) { addCompileError( String.format( "Key field '%s' must be of type String, but is '%s' instead", result.getName(), result.getType().getName()), result); return null; } ClassNode ancestor = ASTHelper.getHighestAncestorDSLObject(target); if (target.equals(ancestor)) return result; FieldNode firstKey = getKeyField(ancestor); if (firstKey == null) { addCompileError( String.format( "Inconsistent hierarchy: Toplevel class %s has no key, but child class %s defines '%s'.", ancestor.getName(), target.getName(), result.getName()), result); return null; } return result; }
private ClassNode createInnerHelperClass( ClassNode buildee, String builderClassName, int fieldsSize) { final String fullName = buildee.getName() + "$" + builderClassName; ClassNode builder = new InnerClassNode(buildee, fullName, PUBLIC_STATIC, OBJECT_TYPE); GenericsType[] gtypes = new GenericsType[fieldsSize]; for (int i = 0; i < gtypes.length; i++) { gtypes[i] = makePlaceholder(i); } builder.setGenericsTypes(gtypes); return builder; }
private Statement checkFinalArgNotOverridden(ClassNode cNode, FieldNode fNode) { final String name = fNode.getName(); Expression value = findArg(name); return new IfStatement( equalsNullExpr(value), new EmptyStatement(), new ThrowStatement( new ConstructorCallExpression( READONLYEXCEPTION_TYPE, new ArgumentListExpression( new ConstantExpression(name), new ConstantExpression(cNode.getName()))))); }
public static void doCast(MethodVisitor mv, ClassNode type) { if (type == ClassHelper.OBJECT_TYPE) return; if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) { unbox(mv, type); } else { mv.visitTypeInsn( CHECKCAST, type.isArray() ? BytecodeHelper.getTypeDescription(type) : BytecodeHelper.getClassInternalName(type.getName())); } }
public static void addMybatisContributionIfNeeded(SourceUnit source, ClassNode classNode) { if (needsMybatisContribution(classNode, source)) { if (LOG.isDebugEnabled()) { LOG.debug( "Injecting " + MybatisContributionHandler.class.getName() + " into " + classNode.getName()); } apply(classNode); } }
/** * Sets this instance as proxy for the given ClassNode. * * @param cn the class to redirect to. If set to null the redirect will be removed */ public void setRedirect(ClassNode cn) { if (isPrimaryNode) throw new GroovyBugError( "tried to set a redirect for a primary ClassNode (" + getName() + "->" + cn.getName() + ")."); if (cn != null) cn = cn.redirect(); if (cn == this) return; redirect = cn; }
/** * This exists to avoid a recursive definition of toString. The default toString in GenericsType * calls ClassNode.toString(), which calls GenericsType.toString(), etc. * * @param genericsType * @param showRedirect * @return the string representing the generic type */ private String genericTypeAsString(GenericsType genericsType, boolean showRedirect) { String ret = genericsType.getName(); if (genericsType.getUpperBounds() != null) { ret += " extends "; for (int i = 0; i < genericsType.getUpperBounds().length; i++) { ClassNode classNode = genericsType.getUpperBounds()[i]; if (classNode.equals(this)) { ret += classNode.getName(); } else { ret += classNode.toString(showRedirect); } if (i + 1 < genericsType.getUpperBounds().length) ret += " & "; } } else if (genericsType.getLowerBound() != null) { ClassNode classNode = genericsType.getLowerBound(); if (classNode.equals(this)) { ret += " super " + classNode.getName(); } else { ret += " super " + classNode; } } return ret; }
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; }
protected Class createClass(byte[] code, ClassNode classNode) { BytecodeProcessor bytecodePostprocessor = unit.getConfiguration().getBytecodePostprocessor(); byte[] fcode = code; if (bytecodePostprocessor != null) { fcode = bytecodePostprocessor.processBytecode(classNode.getName(), fcode); } GroovyClassLoader cl = getDefiningClassLoader(); Class theClass = cl.defineClass( classNode.getName(), fcode, 0, fcode.length, unit.getAST().getCodeSource()); this.loadedClasses.add(theClass); if (generatedClass == null) { ModuleNode mn = classNode.getModule(); SourceUnit msu = null; if (mn != null) msu = mn.getContext(); ClassNode main = null; if (mn != null) main = (ClassNode) mn.getClasses().get(0); if (msu == su && main == classNode) generatedClass = theClass; } return theClass; }
private void injectToStringMethod(ClassNode classNode) { final boolean hasToString = /*GrailsASTUtils.*/ implementsZeroArgMethod(classNode, "toString"); if (!hasToString) { GStringExpression ge = new GStringExpression(classNode.getName() + " : ${id}"); ge.addString(new ConstantExpression(classNode.getName() + " : ")); ge.addValue(new VariableExpression("id")); Statement s = new ReturnStatement(ge); MethodNode mn = new MethodNode( "toString", Modifier.PUBLIC, new ClassNode(String.class), new Parameter[0], new ClassNode[0], s); // if(LOG.isDebugEnabled()) { // LOG.debug("[GrailsDomainInjector] Adding method [toString()] to class [" + // classNode.getName() + "]"); // } classNode.addMethod(mn); } }