SBM offers commands to scan application source code and run recipes against it. Recipes bundle actions to apply source code migrations or find information in the codebase.
An Action
is a single step in a recipe and can be reused by other recipes.
Every Recipe
has at least one Action
and each Recipe and every action has a condition which defines if the recipe and/or it’s actions are applicable.
The condition has access to all resources to evaluate to true
or false
.
If a recipe’s condition evaluates to false
the recipe is not displayed.
Actions with a condition evaluating to true
are applicable and will be executed with the recipe.
When all actions of a recipe evaluate to false
the recipe itself is not applicable.
Recipes can be declared in yaml syntax or provided as Java bean definitions.
-
See initialize-spring-boot-migration.yaml for a recipe in YAML syntax
-
See MigrateMuleToBoot.java for a recipe as Spring bean.
Action is the starting point when developing a recipe.
Every Action has access to all resources and their ASTs through the ProjectContext
.
class MyAction extends AbstractAction {
void apply(ProjectContext context) {
// analyse and modify AST
}
}
After scanning and parsing the source code of a given application a ProjectContext
gets created.
The ProjectContext
acts as facade to the abstract syntax tree (AST) of the project and provides an API to access project resources.
ProjectJavaSources pjs = context.getProjectJavaSources();
ApplicationModules am = context.getApplicationModules()
The ProjectContext
represents the current application state in memory and provides access to all resources.
The API provides methods to retrieve and modify Java source, application modules and build files.
All other resource types can be retrieved using finders.
Finders are useful to access and filter resources.
public interface ProjectResourceFinder<T> {
T apply(ProjectResourceSet projectResourceSet);
}
Finder have access to the ProjectResourceSet
(see [ProjectResourceSet]) to filter/find resources and return the result.
The result is of the same type as the generic type T
.
The ProjectContext provides a search(..)
method to apply Finder.
List<..> resources = projectContext.search(new PathMatchingProjectResourceFinder("/**/some/path/*.file"));
Finders also provide access to specialized resources, resources that are not directly accessible through the ProjectContext Api.
Specialized resources like SpringBootApplicationProperties
, PersistenceXml
, WebXml
, …, can be retrieved by their Finder
s.
void apply(ProjectContext context) {
SpringBootApplicationProperties p = context.search(new SpringBootApplicationPropertiesFinder());
p.getProperty("cloud-profile", "some.property.key")
}
Read the Specialized Resources section to learn how you can provide new Specialized Resources.
The user provides a root directory to scan a project. After scanning the given directory a set of preconditions is checked to verify that the scanned project can be successfully parsed. See [Check Preconditions] to learn how you can provide additional precondition checks.
When all preconditions are met the project resources are parsed and the abstract syntax tree (AST) gets created in memory.
After parsing the project resources a set of ProjectResourceWrapper
s is called and generic resources can be replaced
with more specialized resources providing a specialized API for these resources.
Think of replacing a generic XML file representing persistence.xml
(JPA deployment descriptor) with a specialized
resource representation offering an API to act on a specialized "JPA deployment descriptor".
See Specialized Resources to learn how yo can provide specialized resources.
The user applies a recipe from the list of applicable recipes.
SBM provides the ProjectContext
to the list of applicable Action
s and each Action
modifies the AST through the
ProjectContext
API. These modifications are only represented in memory.
After applying all Action
s of the Recipe
the changes need to be written back to filesystem.
When sbm.gitSupportEnabled
is true
SBM verifies that nothing changed in the scanned project while the recipe was applied.
If the git hash changed or non-indexed resources are found the changes are rolled back, the project must be synced,
re-scanned and the recipe needs to be re-applied.
When git support is disabled or the project is in sync the in-memory representation is written back to the file system.
Since 0.9.0 SBM starts to support multi module applications.
Classes annotated with Spring @RestController
annotation can be found using the FindRestControllerBeans
finder.
List<RestControllerBean> restController = projectContext.search(new FindRestControllerBeans());
List<RestMethod> restMethods = restController.get(0).getRestMethods();
restMethods.get(0).