Skip to content

Instantly share code, notes, and snippets.

@stenis999
Created May 25, 2015 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stenis999/4f97375b3a9527964a8e to your computer and use it in GitHub Desktop.
Save stenis999/4f97375b3a9527964a8e to your computer and use it in GitHub Desktop.
Source files necessary to produce gradle checksum bug when uploading to Amazon S3
package com.me;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@GroovyASTTransformationClass("com.me.impl.DeepCopyASTTransformation")
public @interface DeepCopy {
}
package com.me.impl;
import com.me.DeepCopy;
import org.codehaus.groovy.ast.ASTNode;
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.Parameter;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
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.ReturnStatement;
import org.codehaus.groovy.ast.tools.GeneralUtils;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class DeepCopyASTTransformation extends AbstractASTTransformation {
static final ClassNode MY_TYPE = ClassHelper.make(DeepCopy.class);
static final ClassNode SERIALIZABLE_TYPE = ClassHelper.make(Serializable.class);
static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
private static final ClassNode BYTE_ARRAY_INPUT_STREAM_TYPE = ClassHelper.make(ByteArrayInputStream.class);
private static final ClassNode BYTE_ARRAY_OUTPUT_STREAM_TYPE = ClassHelper.make(ByteArrayOutputStream.class);
private static final ClassNode OBJECT_INPUT_STREAM_TYPE = ClassHelper.make(ObjectInputStream.class);
private static final ClassNode OBJECT_OUTPUT_STREAM_TYPE = ClassHelper.make(ObjectOutputStream.class);
public void visit(ASTNode[] nodes, SourceUnit source) {
init(nodes, source);
AnnotationNode annotationNode = (AnnotationNode) nodes[0];
AnnotatedNode parent = (AnnotatedNode) nodes[1];
if (annotationNode == null || !MY_TYPE.equals(annotationNode.getClassNode())) {
return;
}
if (parent instanceof ClassNode) {
ClassNode cNode = (ClassNode) parent;
checkNotInterface(cNode, MY_TYPE_NAME);
createDeepCopy(cNode);
}
}
private void createDeepCopy(ClassNode cNode) {
if (GeneralUtils.hasDeclaredMethod(cNode, "deepCopy", 0)) {
return;
}
// make sure class node implements Serializable
cNode.addInterface(SERIALIZABLE_TYPE);
BlockStatement body = buildDeepCopyMethodBody();
ClassNode returnType = cNode.getPlainNodeReference();
cNode.addMethod("deepCopy", ACC_PUBLIC, returnType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body);
}
private BlockStatement buildDeepCopyMethodBody() {
BlockStatement body = new BlockStatement();
// def bos = new ByteArrayOutputStream()
Expression bos = new VariableExpression("bos");
Expression newBos = new ConstructorCallExpression(BYTE_ARRAY_OUTPUT_STREAM_TYPE, MethodCallExpression.NO_ARGUMENTS);
body.addStatement(GeneralUtils.declS(bos, newBos));
// def oos = new ObjectOutputStream(bos)
Expression oos = new VariableExpression("oos");
Expression newOos = new ConstructorCallExpression(OBJECT_OUTPUT_STREAM_TYPE, bos);
body.addStatement(GeneralUtils.declS(oos, newOos));
// oos.writeObject(this)
Expression oosWriteObject = new MethodCallExpression(oos, "writeObject", VariableExpression.THIS_EXPRESSION);
body.addStatement(new ExpressionStatement(oosWriteObject));
// oos.flush()
Expression oosFlush = new MethodCallExpression(oos, "flush", MethodCallExpression.NO_ARGUMENTS);
body.addStatement(new ExpressionStatement(oosFlush));
// def bin = new ByteArrayInputStream(bos.toByteArray())
Expression bin = new VariableExpression("bin");
Expression bosToByteArray = new MethodCallExpression(bos, "toByteArray", MethodCallExpression.NO_ARGUMENTS);
Expression newBin = new ConstructorCallExpression(BYTE_ARRAY_INPUT_STREAM_TYPE, bosToByteArray);
body.addStatement(GeneralUtils.declS(bin, newBin));
// def ois = new ObjectInputStream(bin)
Expression ois = new VariableExpression("ois");
Expression newOis = new ConstructorCallExpression(OBJECT_INPUT_STREAM_TYPE, bin);
body.addStatement(GeneralUtils.declS(ois, newOis));
// return ois.readObject()
Expression oisReadObject = new MethodCallExpression(ois, "readObject", MethodCallExpression.NO_ARGUMENTS);
body.addStatement(new ReturnStatement(oisReadObject));
return body;
}
}
package com.me
import org.codehaus.groovy.GroovyBugError
import org.codehaus.groovy.ast.ASTNode
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.expr.ConstantExpression
import org.codehaus.groovy.ast.expr.Expression
import org.codehaus.groovy.ast.expr.PropertyExpression
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.control.messages.Message
import org.codehaus.groovy.control.messages.WarningMessage
import org.codehaus.groovy.syntax.Token
import org.codehaus.groovy.syntax.Types
import org.codehaus.groovy.transform.AbstractASTTransformation
import java.lang.annotation.Annotation
abstract class MyAbstractASTTransformation extends AbstractASTTransformation {
Class<? extends Annotation> annotationClass
ClassNode annotationClassNode
AnnotatedNode annotatedNode
AnnotationNode annotationNode
boolean verificationFailed
MyAbstractASTTransformation(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass
annotationClassNode = ClassHelper.make(annotationClass)
}
String getAnnotationClassName() {
'@'+annotationClass.simpleName
}
void initialize(ASTNode[] nodes, SourceUnit sourceUnit) {
init(nodes, sourceUnit)
this.sourceUnit = sourceUnit
this.annotationClass = annotationClass
verificationFailed = false
setNodes(nodes)
if (verificationFailed) {
throw new GroovyBugError("AST nodes verification failed")
}
}
def setNodes(ASTNode[] nodes) {
verify "ASTNode array should not be null", nodes != null
verify "ASTNode array length should be 2", nodes.length == 2
verify "First ASTNode should be an annotation node", nodes[0] instanceof AnnotationNode
verify "First ASTNode should be annotation for $annotationClass", nodes[0].classNode?.name == annotationClass.name
verify "Second ASTNode should be an annotated node", nodes[1] instanceof AnnotatedNode
annotationNode = nodes[0] as AnnotationNode
annotatedNode = nodes[1] as AnnotatedNode
}
def verify(String message, boolean shouldBeTrue, AnnotatedNode node = annotatedNode) {
if (!shouldBeTrue) {
verificationFailed = true
if (node) {
addError(message, node)
} else {
addError(message)
}
}
}
Object getMemberValue(AnnotationNode node, String name) {
getMemberValue(node, name, null)
}
Object getMemberValue(AnnotationNode node, String name, Object defaultValue) {
Expression member = node.getMember(name)
if (member != null) {
if (member instanceof PropertyExpression) {
def property =(PropertyExpression)member
member = property.property
}
if (member instanceof ConstantExpression) {
Object result = ((ConstantExpression) member).getValue()
if (result != null) {
return result
}
}
}
return defaultValue
}
void addError(String message) {
sourceUnit.errorCollector.addError(Message.create(message, sourceUnit))
}
void addWarning(String message, ASTNode node, int level = WarningMessage.NONE) {
sourceUnit.errorCollector.addWarning(
level, // note warning won't display if level is *higher* than configured limit, i.e. NONE will always be displayed
message,
new Token(Types.UNKNOWN, node.text, node.lineNumber, node.columnNumber),
sourceUnit)
}
void info(String message, String annotatedPartialClassName = null) {
if (annotatedPartialClassName == null || annotatedNode.text.contains(annotatedPartialClassName)) {
addWarning(message, annotatedNode)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment