code transformation with spoon
TRANSCRIPT
![Page 1: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/1.jpg)
Code Transformation with Spoon
Gérard Paligot
![Page 2: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/2.jpg)
Code transformation• Read, generate, analyse or transform.
![Page 3: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/3.jpg)
Code transformation• Read, generate, analyse or transform.
• Used more and more by libraries.
![Page 4: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/4.jpg)
Code transformation• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(String message) { if (message.isEmpty()) { System.out.println("Hello, World!"); } else { System.out.println(message); }}
![Page 5: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/5.jpg)
Code transformation• Read, generate, analyse or transform.
• Used more and more by libraries.
@Log public void sayHello(String message) { if (message.isEmpty()) { System.out.println("Hello, World!"); } else { System.out.println(message); }}
![Page 6: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/6.jpg)
Code transformation• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(@Log String message) { if (message.isEmpty()) { System.out.println("Hello, World!"); } else { System.out.println(message); }}
![Page 7: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/7.jpg)
Code transformation• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(@NotNull String message) { if (message.isEmpty()) { System.out.println("Hello, World!"); } else { System.out.println(message); }}
![Page 8: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/8.jpg)
Library rescue• APT
• JDT
• JavaParser
• JTransformer
• ASM
• pfff
• Others…
![Page 9: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/9.jpg)
JDT• Developed at Eclipse.
![Page 10: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/10.jpg)
JDT• Developed at Eclipse.
• Used in the project Eclipse.
![Page 11: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/11.jpg)
JDT• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
![Page 12: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/12.jpg)
JDT• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
• Read, generate, analyse and transform source code.
![Page 13: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/13.jpg)
JDT• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
• Read, generate, analyse and transform source code.
• API and meta model hard to use and to understand.
![Page 14: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/14.jpg)
APT• Developed at SUN, later by Oracle.
![Page 15: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/15.jpg)
APT• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
![Page 16: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/16.jpg)
APT• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.lang.model.* and javax.annotation.processing.
![Page 17: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/17.jpg)
APT• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.lang.model.* and javax.annotation.processing.
• Well integrated in modernes build-management.
![Page 18: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/18.jpg)
APT• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.lang.model.* and javax.annotation.processing.
• Well integrated in modernes build-management.
• Meta model limited and transformation not allowed.
![Page 19: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/19.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 20: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/20.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 21: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/21.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 22: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/22.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 23: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/23.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 24: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/24.jpg)
@SupportedAnnotationTypes("fr.inria.NotNull") public class TypeProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { roundEnv.getElementsAnnotatedWith(NotNull.class).stream() // .map(e -> "annotation found on " + e.getSimpleName()) // .forEach(System.out::println); for (Element element : roundEnv.getElementsAnnotatedWith(NotNull.class)) { // Editing not possible! } return true; }}
![Page 25: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/25.jpg)
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <id>default-compile</id> <goals> <goal>compile</goal> </goals> <configuration> <compilerArgument>-proc:none</compilerArgument> </configuration> </execution> </executions> </plugin>
![Page 26: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/26.jpg)
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <id>default-compile</id> <goals> <goal>compile</goal> </goals> <configuration> <compilerArgument>-proc:none</compilerArgument> </configuration> </execution> </executions> </plugin>
![Page 27: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/27.jpg)
<dependency> <groupId>fr.inria</groupId> <artifactId>apt</artifactId> <version>${project.parent.version}</version> <optional>true</optional> </dependency>
![Page 28: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/28.jpg)
Spoon• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
![Page 29: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/29.jpg)
Spoon• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille, by Diversify at INRIA Rennes and by the world!
![Page 30: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/30.jpg)
Spoon• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille, by Diversify at INRIA Rennes and by the world!
• Designed for developers to be use easily.
![Page 31: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/31.jpg)
Spoon• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille, by Diversify at INRIA Rennes and by the world!
• Designed for developers to be use easily.
• Source to source code transformation.
![Page 32: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/32.jpg)
Spoon• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille, by Diversify at INRIA Rennes and by the world!
• Designed for developers to be use easily.
• Source to source code transformation.
• Complete and fine-grained Java meta model.
![Page 33: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/33.jpg)
APT
![Page 34: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/34.jpg)
Spoon
http://spoon.gforge.inria.fr/structural_elements.html
![Page 36: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/36.jpg)
Spoon
http://spoon.gforge.inria.fr/code_elements.html
![Page 37: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/37.jpg)
Spoon
![Page 38: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/38.jpg)
How it works?
Input
AST
Processing
Output
![Page 39: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/39.jpg)
Features• Factory
• Query
• Processor
• Template
![Page 40: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/40.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
http://spoon.gforge.inria.fr/processor.html
![Page 41: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/41.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
public class TypeSpoonProcessor extends AbstractAnnotationProcessor<NotNull, CtParameter<?>> { @Override public void process(NotNull annotation, CtParameter<?> element) { } }
http://spoon.gforge.inria.fr/processor.html
![Page 42: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/42.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
public class TypeSpoonProcessor extends AbstractAnnotationProcessor<NotNull, CtParameter<?>> { @Override public void process(NotNull annotation, CtParameter<?> element) { } }
http://spoon.gforge.inria.fr/processor.html
![Page 43: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/43.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
public class TypeSpoonProcessor extends AbstractAnnotationProcessor<NotNull, CtParameter<?>> { @Override public void process(NotNull annotation, CtParameter<?> element) { } }
http://spoon.gforge.inria.fr/processor.html
![Page 44: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/44.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
public class TypeSpoonProcessor extends AbstractAnnotationProcessor<NotNull, CtParameter<?>> { @Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); } }
http://spoon.gforge.inria.fr/processor.html
![Page 45: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/45.jpg)
ProcessorA program analysis is a combination of query and analysis code. In Spoon, this conceptual pair is reified in a processor. A processor is a class that focuses on the analysis of one kind of program elements.
public class TypeSpoonProcessor extends AbstractAnnotationProcessor<NotNull, CtParameter<?>> { @Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); } }
http://spoon.gforge.inria.fr/processor.html
![Page 46: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/46.jpg)
FactoryCreate new elements, fill their data and add them in an existing AST. The factory is the entry point to do that and each factory has them own responsibility. i.e., CoreFactory creates empty nodes and CodeFactory creates a node ready to be printed.
http://spoon.gforge.inria.fr/factories.html
![Page 47: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/47.jpg)
FactoryCreate new elements, fill their data and add them in an existing AST. The factory is the entry point to do that and each factory has them own responsibility. i.e., CoreFactory creates empty nodes and CodeFactory creates a node ready to be printed.
http://spoon.gforge.inria.fr/factories.html
if (message == "null") java.lang.System.out.println("message is null");
![Page 48: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/48.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 49: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/49.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 50: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/50.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 51: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/51.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 52: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/52.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 53: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/53.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 54: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/54.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 55: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/55.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 56: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/56.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 57: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/57.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 58: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/58.jpg)
if (message == "null") java.lang.System.out.println("message is null");
![Page 59: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/59.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 60: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/60.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 61: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/61.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 62: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/62.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 63: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/63.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 64: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/64.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 65: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/65.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 66: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/66.jpg)
TemplateSpoon provides developers a way of writing code transformations: code templates. Those templates are statically type-checked, in order to ensure statically that the generated code will be correct.
http://spoon.gforge.inria.fr/template_definition.html
![Page 67: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/67.jpg)
public class NotNullTemplate extends StatementTemplate { @Parameter CtVariableAccess<?> _access_; public NotNullTemplate(CtVariableAccess<?> _access_) { this._access_ = _access_; } @Override public void statement() throws Throwable { if (_access_.S() == null) { System.out.println("Parameter is null"); } }}
![Page 68: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/68.jpg)
public class NotNullTemplate extends StatementTemplate { @Parameter CtVariableAccess<?> _access_; public NotNullTemplate(CtVariableAccess<?> _access_) { this._access_ = _access_; } @Override public void statement() throws Throwable { if (_access_.S() == null) { System.out.println("Parameter is null"); } }}
![Page 69: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/69.jpg)
public class NotNullTemplate extends StatementTemplate { @Parameter CtVariableAccess<?> _access_; public NotNullTemplate(CtVariableAccess<?> _access_) { this._access_ = _access_; } @Override public void statement() throws Throwable { if (_access_.S() == null) { System.out.println("Parameter is null"); } }}
![Page 70: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/70.jpg)
public class NotNullTemplate extends StatementTemplate { @Parameter CtVariableAccess<?> _access_; public NotNullTemplate(CtVariableAccess<?> _access_) { this._access_ = _access_; } @Override public void statement() throws Throwable { if (_access_.S() == null) { System.out.println("Parameter is null"); } }}
![Page 71: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/71.jpg)
public class NotNullTemplate extends StatementTemplate { @Parameter CtVariableAccess<?> _access_; public NotNullTemplate(CtVariableAccess<?> _access_) { this._access_ = _access_; } @Override public void statement() throws Throwable { if (_access_.S() == null) { System.out.println("Parameter is null"); } }}
![Page 72: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/72.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); final CtVariableAccess<?> parameter = // getFactory().Code().createVariableRead(element.getReference(), false); final CtLiteral<?> nullAccess = getFactory().Code().createLiteral("null"); final CtBinaryOperator<Boolean> binaryOperator = // getFactory().Code().createBinaryOperator(parameter, nullAccess, BinaryOperatorKind.EQ); final CtCodeSnippetStatement snippet = getFactory().Code().createCodeSnippetStatement( "System.out.println(\"" + element.getSimpleName() + " is null\")"); // Creates condition. final CtIf anIf = getFactory().Core().createIf(); anIf.setCondition(binaryOperator); anIf.setThenStatement(snippet.compile()); // Factory final CtExecutable ctExecutable = element.getParent(CtExecutable.class); ctExecutable.getBody().insertBegin(anIf);}
![Page 73: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/73.jpg)
@Override public void process(NotNull annotation, CtParameter<?> element) { System.out.println("annotation found on " + element.getSimpleName()); new NotNullTemplate(parameter).apply(element.getParent(CtType.class)); }
![Page 74: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/74.jpg)
QueryMake a complexe query on a given AST, based on the notion of filter, done in plain Java, in the spirit of an embedded DSL and in one single line of code in the normal cases. i.e., TypeFilter is used to return all elements of a certain type.
Query.getElements(factory, new TypeFilter<>(CtParameter.class));
Query.getElements(element, new TypeFilter<>(CtParameter.class));
element.getElements(new TypeFilter<>(CtParameter.class));
http://spoon.gforge.inria.fr/filter.html
![Page 75: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/75.jpg)
Usage<dependency> <groupId>fr.inria.gforge.spoon</groupId> <artifactId>spoon-core</artifactId> <version>5.1.1</version> </dependency>
final SpoonAPI spoon = new Launcher();spoon.addInputResource("/src/main/java/");spoon.setSourceOutputDirectory("/target/");spoon.addProcessor(new AwesomeProcessor());spoon.run();// Here, make complex query from the factory.
Dependency
API
![Page 76: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/76.jpg)
Usage<plugin> <groupId>fr.inria.gforge.spoon</groupId> <artifactId> spoon-maven-plugin </artifactId> <version>2.2</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <processors> <processor> fr.inria.AwesomeProcessor </processor> </processors> </configuration> </plugin>
Maven Plugin
![Page 77: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/77.jpg)
Usagebuildscript { repositories { mavenCentral() mavenLocal() } dependencies { classpath ‘fr.inria.gforge.spoon:spoon—gradle-plugin:1.0-SNAPSHOT’ } } !apply plugin: "java" apply plugin: "spoon" !spoon { processors = [‘fr.inria.AwesomeProcessor’]}
Gradle Plugin
![Page 78: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/78.jpg)
Thank you!Gérard Paligot
![Page 79: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/79.jpg)
Practical work
![Page 80: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/80.jpg)
#1For each interface, count how many classes implement it.
public interface Delicious { void prepare(Prepare prepare, int time); void make(Cook cook, int time);}
![Page 81: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/81.jpg)
#2
Inserts a probe in all entry methods to display its name and its declaring type.
![Page 82: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/82.jpg)
@Overridepublic void prepare() {}
Before
After
@Overridepublic void prepare() { System.out.println("enter: Tacos - prepare"); }
![Page 83: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/83.jpg)
#2 expert
Inserts a probe in all exit methods to display its name and its declaring type.
![Page 84: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/84.jpg)
#3
Adds a probe (with the invocation of a method named isNotNull) to check all parameters not primitives of a method.
![Page 85: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/85.jpg)
@Overridepublic void prepare(Prepare prepare) {}
Before
After
@Overridepublic void prepare(Prepare prepare) { fr.inria.tp3.Check.isNotNull( prepare, "Parameter %s can't be null.", "prepare");}
![Page 86: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/86.jpg)
#3 expert
Uses an annotation, named @NotNull, to check the parameter annotated.
![Page 87: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/87.jpg)
@Overridepublic void prepare(@NotNull Prepare prepare) {}
Before
After
@Overridepublic void prepare(Prepare prepare) { fr.inria.tp3.Check.isNotNull( prepare, "Parameter %s can't be null.", "prepare");}
![Page 88: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/88.jpg)
#4
Create the annotation @Bound to check the minimum and maximum of a method parameter.
![Page 89: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/89.jpg)
@Overridepublic void prepare(@Bound(min = 0, max = 10) int time) {}
Before
After@Overridepublic void prepare(int time) { if (time > 10.0) throw new RuntimeException( "out of max bound (" + time + " > 10.0"); if (time < 0.0) throw new RuntimeException( "out of min bound (" + time + " < 0.0");}
![Page 90: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/90.jpg)
#5
Create the annotation @RetryOnFailure to relaunch execution of a method if an exception is thrown.
Think to use templates. ;)
![Page 91: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/91.jpg)
@java.lang.Overridepublic void prepare() { int attempt = 0; java.lang.Throwable lastTh = null; while ((attempt++) < 3) { try { // Body of the original code here. } catch (java.lang.Throwable ex) { lastTh = ex; if (false) { ex.printStackTrace(); } try { java.lang.Thread.sleep(50L); } catch (java.lang.InterruptedException ignored) { } } } if (lastTh != null) { throw new java.lang.RuntimeException(lastTh); } }
![Page 92: Code transformation With Spoon](https://reader034.vdocuments.us/reader034/viewer/2022042605/58e8d89d1a28abb3398b6497/html5/thumbnails/92.jpg)
• TP 1: For each interface, count how many classes implement it.
• TP 2: Inserts a probe in all entry methods to display its name and its declaring type.
• TP 2 (expert): Handles exit of methods.
• TP 3: Adds a probe (with the invocation of a method named checkNotNull) to check all parameters not primitives of a method.
• TP 3 (expert): Handles it with an annotation named @NotNull.
• TP 4: Create the annotation @Bound to check the minimum and maximum of a method parameter.
• TP 5 (expert): Create the annotation @RetryOnFailure to relaunch execution of a method if an exception is thrown.