SlideShare ist ein Scribd-Unternehmen logo
1 von 92
Downloaden Sie, um offline zu lesen
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 message) {

if (message.isEmpty()) {

System.out.println("Hello, World!");

} else {

System.out.println(message);

}

}
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);

}

}
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);

}

}
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);

}

}
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, analyse and transform source code.
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.
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.lang.model.* and
javax.annotation.processing.
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.
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.
@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;

}

}
@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;

}

}
@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;

}

}
@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;

}

}
@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;

}

}
@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;

}

}
<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>
<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>
<dependency>

<groupId>fr.inria</groupId>

<artifactId>apt</artifactId>

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

<optional>true</optional>

</dependency>
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, by Diversify at
INRIA Rennes and by the world!
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.
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.
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.
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 processor. A processor is a class that focuses on
the analysis of one kind of program elements.
http://spoon.gforge.inria.fr/processor.html
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
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
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
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
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
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
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");
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 " + 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);

}
@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);

}
@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);

}
@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);

}
@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);

}
@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);

}
@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);

}
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
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");

}

}

}
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");

}

}

}
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");

}

}

}
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");

}

}

}
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");

}

}

}
@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);

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

System.out.println("annotation found on " + element.getSimpleName());



new NotNullTemplate(parameter).apply(element.getParent(CtType.class));


}
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
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
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
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
Thank you!
Gérard Paligot
Practical work
#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);

}
#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 - prepare");

}
#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.inria.tp3.Check.isNotNull(
prepare, "Parameter %s can't be null.", "prepare");

}
#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 prepare) {

fr.inria.tp3.Check.isNotNull(
prepare, "Parameter %s can't be null.", "prepare");

}
#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 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");

}
#5
Create the annotation @RetryOnFailure to relaunch
execution of a method if an exception is thrown.
Think to use templates. ;)
@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);

} 

}
• 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.

Weitere ähnliche Inhalte

Was ist angesagt?

Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
Anton Arhipov
 

Was ist angesagt? (20)

Java7 New Features and Code Examples
Java7 New Features and Code ExamplesJava7 New Features and Code Examples
Java7 New Features and Code Examples
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
 
Java 104
Java 104Java 104
Java 104
 
Write code that writes code!
Write code that writes code!Write code that writes code!
Write code that writes code!
 
Modern Programming in Java 8 - Lambdas, Streams and Date Time API
Modern Programming in Java 8 - Lambdas, Streams and Date Time APIModern Programming in Java 8 - Lambdas, Streams and Date Time API
Modern Programming in Java 8 - Lambdas, Streams and Date Time API
 
55 New Features in Java 7
55 New Features in Java 755 New Features in Java 7
55 New Features in Java 7
 
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go WrongJDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
 
Java concurrency questions and answers
Java concurrency questions and answers Java concurrency questions and answers
Java concurrency questions and answers
 
JDK1.6
JDK1.6JDK1.6
JDK1.6
 
Advance Java Programs skeleton
Advance Java Programs skeletonAdvance Java Programs skeleton
Advance Java Programs skeleton
 
Java 8: the good, the bad and the ugly (JBCNConf 2017)
Java 8: the good, the bad and the ugly (JBCNConf 2017)Java 8: the good, the bad and the ugly (JBCNConf 2017)
Java 8: the good, the bad and the ugly (JBCNConf 2017)
 
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
 
모던자바의 역습
모던자바의 역습모던자바의 역습
모던자바의 역습
 
Annotation Processing in Android
Annotation Processing in AndroidAnnotation Processing in Android
Annotation Processing in Android
 
Java 8 Feature Preview
Java 8 Feature PreviewJava 8 Feature Preview
Java 8 Feature Preview
 
Testing Java Code Effectively
Testing Java Code EffectivelyTesting Java Code Effectively
Testing Java Code Effectively
 
Code generation for alternative languages
Code generation for alternative languagesCode generation for alternative languages
Code generation for alternative languages
 
Static analysis: Around Java in 60 minutes
Static analysis: Around Java in 60 minutesStatic analysis: Around Java in 60 minutes
Static analysis: Around Java in 60 minutes
 
To inject or not to inject: CDI is the question
To inject or not to inject: CDI is the questionTo inject or not to inject: CDI is the question
To inject or not to inject: CDI is the question
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
 

Ähnlich wie Code transformation With Spoon

China Science Challenge
China Science ChallengeChina Science Challenge
China Science Challenge
remko caprio
 
Lucene for Solr Developers
Lucene for Solr DevelopersLucene for Solr Developers
Lucene for Solr Developers
Erik Hatcher
 
Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularity
elliando dias
 

Ähnlich wie Code transformation With Spoon (20)

Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...Write code that writes code! A beginner's guide to Annotation Processing - Ja...
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
 
How to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsHow to Reverse Engineer Web Applications
How to Reverse Engineer Web Applications
 
Annotation processing
Annotation processingAnnotation processing
Annotation processing
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Java For beginners and CSIT and IT students
Java  For beginners and CSIT and IT studentsJava  For beginners and CSIT and IT students
Java For beginners and CSIT and IT students
 
Xopus Application Framework
Xopus Application FrameworkXopus Application Framework
Xopus Application Framework
 
China Science Challenge
China Science ChallengeChina Science Challenge
China Science Challenge
 
SgCodeJam24 Workshop
SgCodeJam24 WorkshopSgCodeJam24 Workshop
SgCodeJam24 Workshop
 
Practical catalyst
Practical catalystPractical catalyst
Practical catalyst
 
High-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig LatinHigh-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig Latin
 
Scala presentationjune112011
Scala presentationjune112011Scala presentationjune112011
Scala presentationjune112011
 
cheat-sheets.pdf
cheat-sheets.pdfcheat-sheets.pdf
cheat-sheets.pdf
 
Lucene for Solr Developers
Lucene for Solr DevelopersLucene for Solr Developers
Lucene for Solr Developers
 
How to analyze your codebase with Exakat using Docker - Longhorn PHP
How to analyze your codebase with Exakat using Docker - Longhorn PHPHow to analyze your codebase with Exakat using Docker - Longhorn PHP
How to analyze your codebase with Exakat using Docker - Longhorn PHP
 
Core java
Core javaCore java
Core java
 
Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularity
 
JavaOne 2017 CON3282 - Code Generation with Annotation Processors: State of t...
JavaOne 2017 CON3282 - Code Generation with Annotation Processors: State of t...JavaOne 2017 CON3282 - Code Generation with Annotation Processors: State of t...
JavaOne 2017 CON3282 - Code Generation with Annotation Processors: State of t...
 
Java Annotation Processing: A Beginner Walkthrough
Java Annotation Processing: A Beginner WalkthroughJava Annotation Processing: A Beginner Walkthrough
Java Annotation Processing: A Beginner Walkthrough
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java
 

Kürzlich hochgeladen

FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
dollysharma2066
 

Kürzlich hochgeladen (20)

The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01
 
Vivazz, Mieres Social Housing Design Spain
Vivazz, Mieres Social Housing Design SpainVivazz, Mieres Social Housing Design Spain
Vivazz, Mieres Social Housing Design Spain
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.ppt
 
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
 
NFPA 5000 2024 standard .
NFPA 5000 2024 standard                                  .NFPA 5000 2024 standard                                  .
NFPA 5000 2024 standard .
 
Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024Water Industry Process Automation & Control Monthly - April 2024
Water Industry Process Automation & Control Monthly - April 2024
 
Glass Ceramics: Processing and Properties
Glass Ceramics: Processing and PropertiesGlass Ceramics: Processing and Properties
Glass Ceramics: Processing and Properties
 
Extrusion Processes and Their Limitations
Extrusion Processes and Their LimitationsExtrusion Processes and Their Limitations
Extrusion Processes and Their Limitations
 
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
 
UNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular ConduitsUNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular Conduits
 
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
 
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELLPVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
PVC VS. FIBERGLASS (FRP) GRAVITY SEWER - UNI BELL
 
Call for Papers - International Journal of Intelligent Systems and Applicatio...
Call for Papers - International Journal of Intelligent Systems and Applicatio...Call for Papers - International Journal of Intelligent Systems and Applicatio...
Call for Papers - International Journal of Intelligent Systems and Applicatio...
 
Java Programming :Event Handling(Types of Events)
Java Programming :Event Handling(Types of Events)Java Programming :Event Handling(Types of Events)
Java Programming :Event Handling(Types of Events)
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 

Code transformation With Spoon

  • 2. Code transformation • Read, generate, analyse or transform.
  • 3. Code transformation • Read, generate, analyse or transform. • Used more and more by libraries.
  • 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. 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. 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. 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. Library rescue • APT • JDT • JavaParser • JTransformer • ASM • pfff • Others…
  • 10. JDT • Developed at Eclipse. • Used in the project Eclipse.
  • 11. JDT • Developed at Eclipse. • Used in the project Eclipse. • Easy to create a Eclipse plugin with JDT.
  • 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. 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. APT • Developed at SUN, later by Oracle.
  • 15. APT • Developed at SUN, later by Oracle. • Adopted by a lot of open-source librairies.
  • 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. 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. 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. @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. @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. @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. @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. @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. @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;
 }
 }
  • 28. Spoon • Developed at INRIA by Renauld Pawlak, Nicolas Petitprez and Carlos Noguera.
  • 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. 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. 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. 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. APT
  • 37. Spoon
  • 39. Features • Factory • Query • Processor • Template
  • 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. 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. 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. 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. 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. 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. 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. 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. if (message == "null")
 java.lang.System.out.println("message is null");
  • 49. if (message == "null")
 java.lang.System.out.println("message is null");
  • 50. if (message == "null")
 java.lang.System.out.println("message is null");
  • 51. if (message == "null")
 java.lang.System.out.println("message is null");
  • 52. if (message == "null")
 java.lang.System.out.println("message is null");
  • 53. if (message == "null")
 java.lang.System.out.println("message is null");
  • 54. if (message == "null")
 java.lang.System.out.println("message is null");
  • 55. if (message == "null")
 java.lang.System.out.println("message is null");
  • 56. if (message == "null")
 java.lang.System.out.println("message is null");
  • 57. if (message == "null")
 java.lang.System.out.println("message is null");
  • 58. if (message == "null")
 java.lang.System.out.println("message is null");
  • 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. @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. @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. @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. @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. @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. @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. 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. 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. 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. 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. 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. 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. @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. @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. 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. 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
  • 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
  • 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. #2 Inserts a probe in all entry methods to display its name and its declaring type.
  • 82. @Override
 public void prepare() {
 
 } Before After @Override
 public void prepare() {
 System.out.println("enter: Tacos - prepare");
 }
  • 83. #2 expert Inserts a probe in all exit methods to display its name and its declaring type.
  • 84. #3 Adds a probe (with the invocation of a method named isNotNull) to check all parameters not primitives of a method.
  • 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. #3 expert Uses an annotation, named @NotNull, to check the parameter annotated.
  • 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. #4 Create the annotation @Bound to check the minimum and maximum of a method parameter.
  • 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. #5 Create the annotation @RetryOnFailure to relaunch execution of a method if an exception is thrown. Think to use templates. ;)
  • 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. • 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.