Code Transformation with
Spoon
Gérard Paligot
Code transformation
• Read, generate, analyse or transform.
Code transformation
• Read, generate, analyse or transform.
• Used more and more by libraries.
Code transformation
• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(String...
Code transformation
• Read, generate, analyse or transform.
• Used more and more by libraries.
@Log
public void sayHello(S...
Code transformation
• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(@Log S...
Code transformation
• Read, generate, analyse or transform.
• Used more and more by libraries.
public void sayHello(@NotNu...
Library rescue
• APT
• JDT
• JavaParser
• JTransformer
• ASM
• pfff
• Others…
JDT
• Developed at Eclipse.
JDT
• Developed at Eclipse.
• Used in the project Eclipse.
JDT
• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
JDT
• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
• Read, generate, a...
JDT
• Developed at Eclipse.
• Used in the project Eclipse.
• Easy to create a Eclipse plugin with JDT.
• Read, generate, a...
APT
• Developed at SUN, later by Oracle.
APT
• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
APT
• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.l...
APT
• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.l...
APT
• Developed at SUN, later by Oracle.
• Adopted by a lot of open-source librairies.
• Accessible by the package javax.l...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
@SupportedAnnotationTypes("fr.inria.NotNull")

public class TypeProcessor extends AbstractProcessor {

@Override

public b...
<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-compiler-plugin</artifactId>

<executions>

<exec...
<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-compiler-plugin</artifactId>

<executions>

<exec...
<dependency>

<groupId>fr.inria</groupId>

<artifactId>apt</artifactId>

<version>${project.parent.version}</version>

<op...
Spoon
• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
Spoon
• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille,...
Spoon
• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille,...
Spoon
• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille,...
Spoon
• Developed at INRIA by Renauld Pawlak, Nicolas
Petitprez and Carlos Noguera.
• Used by Spirals team at INRIA Lille,...
APT
Spoon
http://spoon.gforge.inria.fr/structural_elements.html
Spoon
http://spoon.gforge.inria.fr/references.html
Spoon
http://spoon.gforge.inria.fr/code_elements.html
Spoon
How it works?
Input
AST
Processing
Output
Features
• Factory
• Query
• Processor
• Template
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Processor
A program analysis is a combination of query and
analysis code. In Spoon, this conceptual pair is reified
in a pr...
Factory
Create new elements, fill their data and add them in an
existing AST. The factory is the entry point to do that
and...
Factory
Create new elements, fill their data and add them in an
existing AST. The factory is the entry point to do that
and...
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
if (message == "null")

java.lang.System.out.println("message is null");
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
Template
Spoon provides developers a way of writing code
transformations: code templates. Those templates are
statically t...
public class NotNullTemplate extends StatementTemplate {

@Parameter CtVariableAccess<?> _access_;



public NotNullTempla...
public class NotNullTemplate extends StatementTemplate {

@Parameter CtVariableAccess<?> _access_;



public NotNullTempla...
public class NotNullTemplate extends StatementTemplate {

@Parameter CtVariableAccess<?> _access_;



public NotNullTempla...
public class NotNullTemplate extends StatementTemplate {

@Parameter CtVariableAccess<?> _access_;



public NotNullTempla...
public class NotNullTemplate extends StatementTemplate {

@Parameter CtVariableAccess<?> _access_;



public NotNullTempla...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
@Override public void process(NotNull annotation, CtParameter<?> element) {

System.out.println("annotation found on " + e...
Query
Make a complexe query on a given AST, based on
the notion of filter, done in plain Java, in the spirit of
an embedde...
Usage
<dependency>

<groupId>fr.inria.gforge.spoon</groupId>

<artifactId>spoon-core</artifactId>

<version>5.1.1</version...
Usage
<plugin>

<groupId>fr.inria.gforge.spoon</groupId>

<artifactId>
spoon-maven-plugin
</artifactId>

<version>2.2</ver...
Usage
buildscript {

repositories {

mavenCentral()
mavenLocal()

}

dependencies {

classpath ‘fr.inria.gforge.spoon:spoo...
Thank you!
Gérard Paligot
Practical work
#1
For each interface, count how many classes
implement it.
public interface Delicious {

void prepare(Prepare prepare, in...
#2
Inserts a probe in all entry methods to display its
name and its declaring type.
@Override

public void prepare() {



}
Before
After
@Override

public void prepare() {

System.out.println("enter: Tacos ...
#2 expert
Inserts a probe in all exit methods to display its name
and its declaring type.
#3
Adds a probe (with the invocation of a method
named isNotNull) to check all parameters not
primitives of a method.
@Override

public void prepare(Prepare prepare) {



}
Before
After
@Override

public void prepare(Prepare prepare) {

fr....
#3 expert
Uses an annotation, named @NotNull, to check the
parameter annotated.
@Override

public void prepare(@NotNull Prepare prepare) {



}
Before
After
@Override

public void prepare(Prepare prepar...
#4
Create the annotation @Bound to check the minimum
and maximum of a method parameter.
@Override

public void prepare(@Bound(min = 0, max = 10) int time) {



}
Before
After
@Override

public void prepare(int ...
#5
Create the annotation @RetryOnFailure to relaunch
execution of a method if an exception is thrown.
Think to use templat...
@java.lang.Override

public void prepare() {

int attempt = 0;

java.lang.Throwable lastTh = null;

while ((attempt++) < 3...
• TP 1: For each interface, count how many classes implement it.
• TP 2: Inserts a probe in all entry methods to display i...
Prochain SlideShare
Chargement dans…5
×

Code transformation With Spoon

245 vues

Publié le

Spoon is an open-source library that enables you to transform and analyze Java source code. Due to a complete and fine-grained Java metamodel, you can read and write the AST built by Spoon. In this talk, you'll see all strong concepts and API with an example. Then, you'll see how you can integrate this project in yours.

Publié dans : Ingénierie
0 commentaire
2 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
245
Sur SlideShare
0
Issues des intégrations
0
Intégrations
5
Actions
Partages
0
Téléchargements
6
Commentaires
0
J’aime
2
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Code transformation With Spoon

  1. 1. Code Transformation with Spoon Gérard Paligot
  2. 2. Code transformation • Read, generate, analyse or transform.
  3. 3. Code transformation • Read, generate, analyse or transform. • Used more and more by libraries.
  4. 4. 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);
 }
 }
  5. 5. 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);
 }
 }
  6. 6. 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);
 }
 }
  7. 7. 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);
 }
 }
  8. 8. Library rescue • APT • JDT • JavaParser • JTransformer • ASM • pfff • Others…
  9. 9. JDT • Developed at Eclipse.
  10. 10. JDT • Developed at Eclipse. • Used in the project Eclipse.
  11. 11. JDT • Developed at Eclipse. • Used in the project Eclipse. • Easy to create a Eclipse plugin with JDT.
  12. 12. JDT • Developed at Eclipse. • Used in the project Eclipse. • Easy to create a Eclipse plugin with JDT. • Read, generate, analyse and transform source code.
  13. 13. 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.
  14. 14. APT • Developed at SUN, later by Oracle.
  15. 15. APT • Developed at SUN, later by Oracle. • Adopted by a lot of open-source librairies.
  16. 16. 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.
  17. 17. 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.
  18. 18. 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.
  19. 19. @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;
 }
 }
  20. 20. @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;
 }
 }
  21. 21. @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;
 }
 }
  22. 22. @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;
 }
 }
  23. 23. @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;
 }
 }
  24. 24. @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;
 }
 }
  25. 25. <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>
  26. 26. <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>
  27. 27. <dependency>
 <groupId>fr.inria</groupId>
 <artifactId>apt</artifactId>
 <version>${project.parent.version}</version>
 <optional>true</optional>
 </dependency>
  28. 28. Spoon • Developed at INRIA by Renauld Pawlak, Nicolas Petitprez and Carlos Noguera.
  29. 29. 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!
  30. 30. 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.
  31. 31. 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.
  32. 32. 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.
  33. 33. APT
  34. 34. Spoon http://spoon.gforge.inria.fr/structural_elements.html
  35. 35. Spoon http://spoon.gforge.inria.fr/references.html
  36. 36. Spoon http://spoon.gforge.inria.fr/code_elements.html
  37. 37. Spoon
  38. 38. How it works? Input AST Processing Output
  39. 39. Features • Factory • Query • Processor • Template
  40. 40. Processor A 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
  41. 41. Processor A 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
  42. 42. Processor A 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
  43. 43. Processor A 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
  44. 44. Processor A 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
  45. 45. Processor A 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
  46. 46. Factory Create 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
  47. 47. Factory Create 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");
  48. 48. if (message == "null")
 java.lang.System.out.println("message is null");
  49. 49. if (message == "null")
 java.lang.System.out.println("message is null");
  50. 50. if (message == "null")
 java.lang.System.out.println("message is null");
  51. 51. if (message == "null")
 java.lang.System.out.println("message is null");
  52. 52. if (message == "null")
 java.lang.System.out.println("message is null");
  53. 53. if (message == "null")
 java.lang.System.out.println("message is null");
  54. 54. if (message == "null")
 java.lang.System.out.println("message is null");
  55. 55. if (message == "null")
 java.lang.System.out.println("message is null");
  56. 56. if (message == "null")
 java.lang.System.out.println("message is null");
  57. 57. if (message == "null")
 java.lang.System.out.println("message is null");
  58. 58. if (message == "null")
 java.lang.System.out.println("message is null");
  59. 59. @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);
 }
  60. 60. @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);
 }
  61. 61. @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);
 }
  62. 62. @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);
 }
  63. 63. @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);
 }
  64. 64. @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);
 }
  65. 65. @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);
 }
  66. 66. Template Spoon 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
  67. 67. 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");
 }
 }
 }
  68. 68. 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");
 }
 }
 }
  69. 69. 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");
 }
 }
 }
  70. 70. 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");
 }
 }
 }
  71. 71. 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");
 }
 }
 }
  72. 72. @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);
 }
  73. 73. @Override public void process(NotNull annotation, CtParameter<?> element) {
 System.out.println("annotation found on " + element.getSimpleName());
 
 new NotNullTemplate(parameter).apply(element.getParent(CtType.class)); 
 }
  74. 74. Query Make 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
  75. 75. 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
  76. 76. 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
  77. 77. Usage buildscript {
 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
  78. 78. Thank you! Gérard Paligot
  79. 79. Practical work
  80. 80. #1 For each interface, count how many classes implement it. public interface Delicious {
 void prepare(Prepare prepare, int time);
 
 void make(Cook cook, int time);
 }
  81. 81. #2 Inserts a probe in all entry methods to display its name and its declaring type.
  82. 82. @Override
 public void prepare() {
 
 } Before After @Override
 public void prepare() {
 System.out.println("enter: Tacos - prepare");
 }
  83. 83. #2 expert Inserts a probe in all exit methods to display its name and its declaring type.
  84. 84. #3 Adds a probe (with the invocation of a method named isNotNull) to check all parameters not primitives of a method.
  85. 85. @Override
 public void prepare(Prepare prepare) {
 
 } Before After @Override
 public void prepare(Prepare prepare) {
 fr.inria.tp3.Check.isNotNull( prepare, "Parameter %s can't be null.", "prepare");
 }
  86. 86. #3 expert Uses an annotation, named @NotNull, to check the parameter annotated.
  87. 87. @Override
 public void prepare(@NotNull Prepare prepare) {
 
 } Before After @Override
 public void prepare(Prepare prepare) {
 fr.inria.tp3.Check.isNotNull( prepare, "Parameter %s can't be null.", "prepare");
 }
  88. 88. #4 Create the annotation @Bound to check the minimum and maximum of a method parameter.
  89. 89. @Override
 public void prepare(@Bound(min = 0, max = 10) int time) {
 
 } Before After @Override
 public 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");
 }
  90. 90. #5 Create the annotation @RetryOnFailure to relaunch execution of a method if an exception is thrown. Think to use templates. ;)
  91. 91. @java.lang.Override
 public 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);
 } 
 }
  92. 92. • 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.

×