Created
May 25, 2015 13:09
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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