Commit fd2583ed authored by Andy Wilkinson's avatar Andy Wilkinson

Support concise @Grab on all types of imports

Previously, the automatic addition of the group and version to a
@Grab annotation based on the module name would only work on standard
import statements. This commit adds support for this functionality
on wildcard imports, static imports and wildcard static imports.

All of the following are now supported:

@Grab('spring-core')
import org.springframework.util.Assert

@Grab('spring-core')
import org.springframework.util.*

@Grab('spring-core')
import static org.springframework.util.Assert.isTrue

@Grab('spring-core')
import static org.springframework.util.Assert.*
parent 640b9d26
......@@ -21,6 +21,7 @@ import groovy.lang.Grab;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.codehaus.groovy.ast.ASTNode;
......@@ -60,9 +61,24 @@ public class ResolveDependencyCoordinatesTransformation implements ASTTransforma
for (ASTNode node : nodes) {
if (node instanceof ModuleNode) {
ModuleNode module = (ModuleNode) node;
visitAnnotatedNode(module.getPackage());
for (ImportNode importNode : module.getImports()) {
visitAnnotatedNode(importNode);
}
for (ImportNode importNode : module.getStarImports()) {
visitAnnotatedNode(importNode);
}
for (Map.Entry<String, ImportNode> entry : module.getStaticImports()
.entrySet()) {
visitAnnotatedNode(entry.getValue());
}
for (Map.Entry<String, ImportNode> entry : module.getStaticStarImports()
.entrySet()) {
visitAnnotatedNode(entry.getValue());
}
for (ClassNode classNode : module.getClasses()) {
visitAnnotatedNode(classNode);
classNode.visitContents(classVisitor);
......@@ -72,9 +88,12 @@ public class ResolveDependencyCoordinatesTransformation implements ASTTransforma
}
private void visitAnnotatedNode(AnnotatedNode annotatedNode) {
for (AnnotationNode annotationNode : annotatedNode.getAnnotations()) {
if (GRAB_ANNOTATION_NAMES.contains(annotationNode.getClassNode().getName())) {
transformGrabAnnotation(annotationNode);
if (annotatedNode != null) {
for (AnnotationNode annotationNode : annotatedNode.getAnnotations()) {
if (GRAB_ANNOTATION_NAMES.contains(annotationNode.getClassNode()
.getName())) {
transformGrabAnnotation(annotationNode);
}
}
}
}
......@@ -138,5 +157,6 @@ public class ResolveDependencyCoordinatesTransformation implements ASTTransforma
public void visitAnnotations(AnnotatedNode node) {
visitAnnotatedNode(node);
}
}
}
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed 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.springframework.boot.cli.compiler.transformation;
import groovy.lang.Grab;
import java.util.Arrays;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.ast.PackageNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.VariableScope;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.io.ReaderSource;
import org.codehaus.groovy.transform.ASTTransformation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.cli.compiler.ArtifactCoordinatesResolver;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for {@link ResolveDependencyCoordinatesTransformation}
*
* @author Andy Wilkinson
*/
public final class ResolveDependencyCoordinatesTransformationTests {
private final SourceUnit sourceUnit = new SourceUnit((String) null,
(ReaderSource) null, null, null, null);
private final ModuleNode moduleNode = new ModuleNode(this.sourceUnit);
private final AnnotationNode grabAnnotation = createGrabAnnotation();
private final ArtifactCoordinatesResolver coordinatesResolver = mock(ArtifactCoordinatesResolver.class);
private final ASTTransformation transformation = new ResolveDependencyCoordinatesTransformation(
this.coordinatesResolver);
@Before
public void setupExpectations() {
when(this.coordinatesResolver.getGroupId("spring-core")).thenReturn(
"org.springframework");
when(this.coordinatesResolver.getVersion("spring-core")).thenReturn("4.0.0.RC1");
}
@Test
public void transformationOfAnnotationOnImport() {
this.moduleNode.addImport(null, null, Arrays.asList(this.grabAnnotation));
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnStarImport() {
this.moduleNode.addStarImport("org.springframework.util",
Arrays.asList(this.grabAnnotation));
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnStaticImport() {
this.moduleNode.addStaticImport(null, null, null,
Arrays.asList(this.grabAnnotation));
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnStaticStarImport() {
this.moduleNode.addStaticStarImport(null, null,
Arrays.asList(this.grabAnnotation));
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnPackage() {
PackageNode packageNode = new PackageNode("test");
packageNode.addAnnotation(this.grabAnnotation);
this.moduleNode.setPackage(packageNode);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnClass() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
classNode.addAnnotation(this.grabAnnotation);
this.moduleNode.addClass(classNode);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnAnnotation() {
}
@Test
public void transformationOfAnnotationOnField() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
this.moduleNode.addClass(classNode);
FieldNode fieldNode = new FieldNode("test", 0, new ClassNode(Object.class),
classNode, null);
classNode.addField(fieldNode);
fieldNode.addAnnotation(this.grabAnnotation);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnConstructor() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
this.moduleNode.addClass(classNode);
ConstructorNode constructorNode = new ConstructorNode(0, null);
constructorNode.addAnnotation(this.grabAnnotation);
classNode.addMethod(constructorNode);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnMethod() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
this.moduleNode.addClass(classNode);
MethodNode methodNode = new MethodNode("test", 0, new ClassNode(Void.class),
new Parameter[0], new ClassNode[0], null);
methodNode.addAnnotation(this.grabAnnotation);
classNode.addMethod(methodNode);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnMethodParameter() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
this.moduleNode.addClass(classNode);
Parameter parameter = new Parameter(new ClassNode(Object.class), "test");
parameter.addAnnotation(this.grabAnnotation);
MethodNode methodNode = new MethodNode("test", 0, new ClassNode(Void.class),
new Parameter[] { parameter }, new ClassNode[0], null);
classNode.addMethod(methodNode);
assertGrabAnnotationHasBeenTransformation();
}
@Test
public void transformationOfAnnotationOnLocalVariable() {
ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
this.moduleNode.addClass(classNode);
DeclarationExpression declarationExpression = new DeclarationExpression(
new VariableExpression("test"), null, new ConstantExpression("test"));
declarationExpression.addAnnotation(this.grabAnnotation);
BlockStatement code = new BlockStatement(
Arrays.asList((Statement) new ExpressionStatement(declarationExpression)),
new VariableScope());
MethodNode methodNode = new MethodNode("test", 0, new ClassNode(Void.class),
new Parameter[0], new ClassNode[0], code);
classNode.addMethod(methodNode);
assertGrabAnnotationHasBeenTransformation();
}
private AnnotationNode createGrabAnnotation() {
ClassNode classNode = new ClassNode(Grab.class);
AnnotationNode annotationNode = new AnnotationNode(classNode);
annotationNode.addMember("value", new ConstantExpression("spring-core"));
return annotationNode;
}
private void assertGrabAnnotationHasBeenTransformation() {
this.transformation.visit(new ASTNode[] { this.moduleNode }, this.sourceUnit);
assertEquals("org.springframework", getGrabAnnotationMemberAsString("group"));
assertEquals("spring-core", getGrabAnnotationMemberAsString("module"));
assertEquals("4.0.0.RC1", getGrabAnnotationMemberAsString("version"));
}
private Object getGrabAnnotationMemberAsString(String memberName) {
Expression expression = this.grabAnnotation.getMember(memberName);
if (expression instanceof ConstantExpression) {
return ((ConstantExpression) expression).getValue();
}
else if (expression == null) {
return null;
}
else {
throw new IllegalStateException("Member '" + memberName
+ "' is not a ConstantExpression");
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment