4. Introduction
motivation
ā¢
Donāt repeat yourself (DRY) principle. Multiple layer architectures
contains lots of wrappers, which might be generated. E.g. Tests, DAOs,
Facades..
ā¢
The application domain relevance. The business rules / domain logic
canāt be generated (really?). We need to focus on this!
ā¢
Code review of ALL contributors. Who ļ¬xes the code?
6. Introduction
What are coding conventions?
ācoding conventions are a set of guidelines for a speciļ¬c programming
language that recommend programming style, practices and methods for
each aspect of a piece program written in this language.ā wikipedia
9. Introduction
walkmod
ā¢
automatizes the practice of code conventions in development teams
(i.e license usage).
ā¢
automatizes the resolution of problems detected by code quality tools
(i.e PMD, , sonar, findbugs).
ā¢
automatizes the development and repetitive tasks i.e: creating basic
CRUD services for the entire model.
ā¢
automatizes global code changes: i.e refactorings.
10. Introduction
walkmod is open!
ā¢
ā¢
ā¢
ā¢
ā¢
open source: feel free to suggest changes!
free for everybody: tell it to your boss!
extensible by plugins do it yourself and share them! DIY+S
editor/IDE independent
community support
12. how it works
ā¢ All conventions are applied
with blocks of
transformations for each
source ļ¬le.
ā¢ Transformations may
update the same sources or
creating/updating another
ones.
workflow
13. how it works
overview
ā¢
reader: reads the sources. i.e retrieves all files from a directory
recursively.
ā¢
ā¢
walker: executes a chain of transformations for each source.
ā¢
writer: writes the sources. i.e using the eclipse formatter.
transformation: updates or creates sources for the following
transformation. Transformations are connected like a pipe through a
shared context.
14. how it works
reader
ā¢
ā¢
ā¢
ā¢
Reads the sources. By default, reads the folder src/main/java.
Works with multiple include/exclude rules.
Creates a resource object, whose content is iterated from the walker.
Works for sources of any programming language. The resource object
could be a source folder, a parsed json ļ¬le, etc..
15. how it works
walker
ā¢
Executes a chain of transformations for each object allocated in a
resource. i.e all java source files of an specific folder.
ā¢
merges the output produced by transformations with existent
resources.
ā¢
ā¢
invokes the writer with the ļ¬nal (and merged) output.
analyzes and reports which changes have been produced by the chain
of transformations in each object.
17. how it works
writer
ā¢
writes each object allocated in a resource. i.e all java source files of a
specific folder.
ā¢
ā¢
Has include/exclude rules.
There are useful writer implementations, such as the storage of the
contents of a toString() object method or the eclipse formatter.
22. transformations
why scripts?
ā¢
ā¢
ā¢
Scripts allow the design of inline transformations.
Scripts should be used to apply simple modifications in source ļ¬les.
Support for multiple languages. Those which implement the standard
Java scripting interface. i.e. groovy, javascript, python..
24. transformations
why visitors?
ā¢
ā¢
Visitors are developed and compiled in java.
ā¢
Visitors should be used to apply complex modifications in source ļ¬les.
To include transformations as plugins to be shared inside the
community.
25. transformations
visitor transformations
public class HelloVisitor extends VoidVisitor<VisitorContext>{
...
@Overwrite
public void visit(MethodDeclaration md, VisitorContext ctx){
//TODO
}
@Overwrite
public void visit(FieldDeclaration fd, VisitorContext ctx){
//TODO
}
...
}
28. query engine
query engine
ā¢
ā¢
Write less to do the same!
ā¢
The default query language is gPath (groovy), but you can change it for
your favorite language.
ā¢
Common used large query expressions can be referenced from Alias.
āTypeDeclaration.metaClass.getMethods = { -> delegate.members.findAll({it instanceof MethodDeclaration}); }ā
All queries have an object context and a query expression. By default, the
context is the root element of a parsed source ļ¬le.
29. query engine
MethodDeclaration method = null;
Collection members = type.getMembers();
Iterator it = members.iterator();
while (it.hasNext()){
BodyDeclaration member = (BodyDeclaration)it.next();
if (member instance of MethodDeclararion){
MethodDeclarion aux = (MethodDeclaration) member;
if(āexecuteā.equals(aux.getName()){
method = aux;
break;
}
}
}
type.methods.find({it.name.equals(āexecuteā)})
30. query engine
queries from templates
Using the query object: ${query.resolve(āexprā)}.
import org.apache.log4j.Logger;
public class ${query.resolve("type.name")}{
public static Logger log = Logger.getLogger(${query.resolve("type.name")}.class);
}
template to add Loggers
31. query engine
queries from scripts
accessing through a binding called query
..
for( type in node.types) {
def result = query.resolve(type, āmethodsā);
...
}
...
groovy script querying the type methods
32. query engine
queries from visitors
Implementing QueryEngineAware or extending VisitorSupport.
public class MyVisitor extends VisitorSupport{
@Overwrite
public void visit(TypeDeclaration td, VisitorContext ctx){
Object result = query(
td, //context
āmethods.find({it.name.equals(āfooā)})ā //expr
);
}
}
visitor code with a gpath query
34. merge engine
why a merge engine?
ā¢
To avoid duplicate results by transformations (i.e duplicate a method)
in existing code.
ā¢
Simplify transformations. Otherwise, transformations must check many
conditions to avoid repeating code or overwriting it.
ā¢
Sometimes, developer changes (i.e. adding a new method) must be
respected by the engine.
36. merge engine
semantic merge
ā¢
Code is merged according to the meaning of its elements instead of
simply merging text.
ā¢
Only elements with the same identifier are merged. Indentiļ¬able
element types must implement the interface mergeable.
37. merge engine
previous concepts
ā¢
ā¢
local object is the current version of an element.
remote object is the modiļ¬ed version of an element generated by a
single transformation. It may be a fragment to add in a local object.
38. merge engine
merge policies
Conļ¬gurable and extensible merge policies for each object type.
Object
merge
policy
Finds the equivalent local version of a remote (and thus,
generated) object and merge recursively their children.
These objects must be identifiable to be searched and found.
These policies should be applied for fields, , methods, , types ā¦
Type select which merge action do for local and remote objects which are
merge not identiļ¬able, although being instances of the same class. i.e policies
policy for the statements of an existent method.
39. merge engine
object merge policies
ā¢
append policy only writes new values for null ļ¬elds. Otherwise, these
are not modiļ¬ed.
ā¢
overwrite policy modiļ¬es all ļ¬eld values of a local object for those
generated by a transformation.
40. merge engine
type merge policies
ā¢
assign policy only writes the remote values. i.e replacing the list of
statements of a method for the generated list.
ā¢
unmodify policy only writes the local values. i.e to respect the
developer changes in the statements of an old transformation.
ā¢
addall policy that appends the remote values into the local values.
42. plugins
why and how to
extend walkmod?
ā¢
You can extend walkmod with new components or override the
existing ones (visitors, readers, writers, walkers, merge policiesā¦)
ā¢
Creating new plugins (java libraries) and deploying them into a maven
repository (public or private). See repo.maven.apache.org
ā¢
All walkmod extensions need a plugin descriptor of their components
in the META-INF/walkmod directory inside the jar library.
43. plugins
plugin descriptor
ā¢
Plugin descriptor is a XML file with the name walkmod-xxx-plugin.xml
which follows the spring bean conļ¬guration.
ā¢
New readers, writers, walkers or transformations must be speciļ¬ed
with a unique name āgroupId:artifactId:nameā as a spring bean in the
plugin descriptor.
<beans>
...
<bean id="walkmod:commons:import-cleaner" class="org.walkmod.visitors.ImportOrganizer" />
...
</beans>
45. plugins
plugin usage (II)
Beans declared in a plugin descriptor can be referenced from walkmod.xml
using the type attribute.
<walkmod>
<plugins>
<plugin groupId="walkmod" artifactId="walkmod-commons-plugin" version="1.0">
</plugin>
</plugins>
<chain name="my-chain">
...
<transformation type="walkmod:commons:imports-cleaner" />
...
</chain>
</walkmod>
46. plugins
plugins backend
ā¢
Walkmod embeds apache ivy to download plugins from maven
repositories in runtime.
ā¢
Custom repositories are in ${walkmod-home}/conf/ivysettings.xml
ā¢
All plugin jars and their dependencies are files loaded dynamically into
a new classloader.
ā¢
All beans used and declared in plugin descriptors are resolved by the
spring source engine using the new classloader.
48. roadmap
next steps
ā¢
modularization: split the project in modules in GitHub and deploy them in a
Maven public repository.
ā¢
ā¢
Java 8 support (lambda expressions)
ā¢
- less configuration: reutilization by inheritance / include rules of the XML
elements.
ā¢
saas: publish online services for running walkmod and all its plugins (also
private).
+ plugins: Create and publish new plugins (e.g. refactoring or support for other
programming languages).