Improving A Personal Programming Process Using Sensei
For this post, I've recreated a 'bad' coding approach that I used when I was learning JUnit, and will demonstrate how to convert the "bad'pattern to an agreed, and "better', coding pattern using Sensei.
When I was learning JUnit, I could only keep so much in my head at any one time. I constantly forgot how to skip tests when they were not working.
If we are working in a team then we can use code reviews on pull requests to help enforce coding styles. And we can shorten the feedback cycle when pair programming with a more experienced programmer.
We can also augment our process with tooling and have the tools prompt us to do the right thing. Thoughtworks described this as "tools over rules," in their Technology Radar listing for Sensei, to: "make it easy to do the right thing over applying checklist-like governance rules and procedures"
Disabling a JUnit Test
Ideally, I would, as we all know, use the @Disabled annotation and write:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
But, when learning, I had to train myself to use @Disabled.
When I forgot how to disable a Test method I would remove the @Test annotation and rename the test:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
It wasn't good, but it got the job done. I didn't have something like Sensei to help me remember and so I fell into using poor coding patterns.
The tasks I've taken on board for this post are to:
- Create a rule which finds methods that have been 'skipped' or 'disabled' by renaming the method.
- Create a QuickFix to rename the method and add both an @Test and @Disabled annotation.
Recipe Settings
The first step I take with Sensei is to "add new recipe" and search for the coding pattern I want the recipe to act on.
Name: JUnit: Make @Disabled @Test from SKIPTHIS
Short Description: Stop naming methods SKIPTHIS, use @Disabled @Test instead
And my search is very simple. I use a basic regex to match the method name.
search:
method:
name:
matches: "SKIPTHIS.*"

QuickFix Settings
The QuickFix is a little more complicated because it will rewrite the code, and I'll use a few steps to achieve my final code.
I want to:
- add an @Test annotation to the method
- add an @Disabled annotation to the method
- amend the method name
Adding the annotations is simple enough using the addAnnotation fix. If I use a fully qualified name for the annotation then Sensei will automatically add the imports for me.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
actions:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
The actual renaming seems a little more complicated but I'm just using a regex replacement, and the generic way to do this with Sensei is to use sed in a rewrite action.
Because the rewrite actions are Mustache templates, Sensei has some functional extensions in the template mechanism. A function is represented with {{#...}} so for sed the function is {{#sed}}. The function takes two comma-separated arguments.
The first argument is the sed statement:
- s/(.*) SKIPTHIS(.*)/$1 $2/
The second argument is the String to apply the sed statement to, which in this case is the method itself, and this is represented in the Mustache variables as:
- {{{.}}}
Giving me the rewrite action of:
- rewrite:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

The sed implementation requires that when the arguments themselves contain commas, they are wrapped with {{#encodeString}} and {{/encodeString}} - e.g. {{#encodeString}}{{{.}}}{{/encodeString}}
Reverse Recipe
Since this is an example, and we might want to use this in demos, I wanted to explore how to reverse out the above change using a Sensei recipe.
Thinking it through I want to find a method annotated with @Disabled but only in the class SkipThisTest where I do the demo:
Name: JUnit: demo in SkipThisTest remove @Disabled and revert to SKIPTHIS
Short Description: remove @Disabled and revert to SKIPTHIS for demo purposes in the project
Level: warning
The Recipe Settings Search is very simple, matching the annotation in a specific class.
search:
method:
annotation:
type: "Disabled"
in:
class:
name: "SkipThisTest"
To avoid making the code look like it is an error I defined the general setting on the recipe to be a Warning. Warnings are shown with highlights in the code and it doesn't make the code look like it has a major problem.
For the Quick fix, since we have matched the method, I use the rewrite action and populate the template using the variables.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
I add every variable except the modifier (since I want to get rid of the annotations) and add the SKIPTHIS text into the template.
This fix has the weakness that by removing the modifiers, I remove any other annotations as well.
Add another Action
I can add another named fix, to give me a choice when the alt+enter is used to display the QuickFix.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
- name: "Remove Disabled, keep other annotations, and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}\n\
{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
Here, I added an additional line in the new Quick Fix.
{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}
This takes the modifier list, encodes it as a string, then uses sed to remove the line with @Disabled from the string, but leaves all other lines in the modifier, i.e. it leaves all other annotations alone.
NOTE: Remember to add the "," in the sed, otherwise you will see a comment added to your preview. This is how Sensei alerts you to syntax errors in the sed command.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Nested sed calls
I was lucky that I could match both the @Disabled and @Test in a single search and replace.
If the code is more complicated and I wanted to have a sequence of sed commands then I can do that by nesting them:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
In the above example, I apply the @Test replacement to the results of applying the @Disabled replacement on the {{{ modifierList }}}.
Summary
sed is a very flexible way to achieve code rewriting and it is possible to nest the sed function calls for complicated rewrite conditions.
Recipes like this often end up being temporary because we are using them to improve our programming process, and once we have built up the muscle memory and no longer use the poor programming pattern we can remove or disable them in the Cookbook.
---
You can install Sensei from within IntelliJ using "Preferences \ Plugins" (Mac) or "Settings \ Plugins" (Windows) then just search for "sensei secure code".
All the code for this blog post can be found on GitHub in the `junitexamples` module of our blog examples repository https://github.com/SecureCodeWarrior/sensei-blog-examples


Learn how to use code reviews on pull requests to help enforce coding styles. And shorten the feedback cycle when pair programming with a more experienced programmer.
Alan Richardson has more than twenty years of professional IT experience, working as a developer and at every level of the testing hierarchy from Tester through to Head of Testing. Head of Developer Relations at Secure Code Warrior, he works directly with teams, to improve the development of quality secure code. Alan is the author of four books including “Dear Evil Tester”, and “Java For Testers”. Alan has also created online training courses to help people learn Technical Web Testing and Selenium WebDriver with Java. Alan posts his writing and training videos on SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, and CompendiumDev.co.uk.

Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.
Book a demoAlan Richardson has more than twenty years of professional IT experience, working as a developer and at every level of the testing hierarchy from Tester through to Head of Testing. Head of Developer Relations at Secure Code Warrior, he works directly with teams, to improve the development of quality secure code. Alan is the author of four books including “Dear Evil Tester”, and “Java For Testers”. Alan has also created online training courses to help people learn Technical Web Testing and Selenium WebDriver with Java. Alan posts his writing and training videos on SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, and CompendiumDev.co.uk.


For this post, I've recreated a 'bad' coding approach that I used when I was learning JUnit, and will demonstrate how to convert the "bad'pattern to an agreed, and "better', coding pattern using Sensei.
When I was learning JUnit, I could only keep so much in my head at any one time. I constantly forgot how to skip tests when they were not working.
If we are working in a team then we can use code reviews on pull requests to help enforce coding styles. And we can shorten the feedback cycle when pair programming with a more experienced programmer.
We can also augment our process with tooling and have the tools prompt us to do the right thing. Thoughtworks described this as "tools over rules," in their Technology Radar listing for Sensei, to: "make it easy to do the right thing over applying checklist-like governance rules and procedures"
Disabling a JUnit Test
Ideally, I would, as we all know, use the @Disabled annotation and write:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
But, when learning, I had to train myself to use @Disabled.
When I forgot how to disable a Test method I would remove the @Test annotation and rename the test:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
It wasn't good, but it got the job done. I didn't have something like Sensei to help me remember and so I fell into using poor coding patterns.
The tasks I've taken on board for this post are to:
- Create a rule which finds methods that have been 'skipped' or 'disabled' by renaming the method.
- Create a QuickFix to rename the method and add both an @Test and @Disabled annotation.
Recipe Settings
The first step I take with Sensei is to "add new recipe" and search for the coding pattern I want the recipe to act on.
Name: JUnit: Make @Disabled @Test from SKIPTHIS
Short Description: Stop naming methods SKIPTHIS, use @Disabled @Test instead
And my search is very simple. I use a basic regex to match the method name.
search:
method:
name:
matches: "SKIPTHIS.*"

QuickFix Settings
The QuickFix is a little more complicated because it will rewrite the code, and I'll use a few steps to achieve my final code.
I want to:
- add an @Test annotation to the method
- add an @Disabled annotation to the method
- amend the method name
Adding the annotations is simple enough using the addAnnotation fix. If I use a fully qualified name for the annotation then Sensei will automatically add the imports for me.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
actions:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
The actual renaming seems a little more complicated but I'm just using a regex replacement, and the generic way to do this with Sensei is to use sed in a rewrite action.
Because the rewrite actions are Mustache templates, Sensei has some functional extensions in the template mechanism. A function is represented with {{#...}} so for sed the function is {{#sed}}. The function takes two comma-separated arguments.
The first argument is the sed statement:
- s/(.*) SKIPTHIS(.*)/$1 $2/
The second argument is the String to apply the sed statement to, which in this case is the method itself, and this is represented in the Mustache variables as:
- {{{.}}}
Giving me the rewrite action of:
- rewrite:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

The sed implementation requires that when the arguments themselves contain commas, they are wrapped with {{#encodeString}} and {{/encodeString}} - e.g. {{#encodeString}}{{{.}}}{{/encodeString}}
Reverse Recipe
Since this is an example, and we might want to use this in demos, I wanted to explore how to reverse out the above change using a Sensei recipe.
Thinking it through I want to find a method annotated with @Disabled but only in the class SkipThisTest where I do the demo:
Name: JUnit: demo in SkipThisTest remove @Disabled and revert to SKIPTHIS
Short Description: remove @Disabled and revert to SKIPTHIS for demo purposes in the project
Level: warning
The Recipe Settings Search is very simple, matching the annotation in a specific class.
search:
method:
annotation:
type: "Disabled"
in:
class:
name: "SkipThisTest"
To avoid making the code look like it is an error I defined the general setting on the recipe to be a Warning. Warnings are shown with highlights in the code and it doesn't make the code look like it has a major problem.
For the Quick fix, since we have matched the method, I use the rewrite action and populate the template using the variables.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
I add every variable except the modifier (since I want to get rid of the annotations) and add the SKIPTHIS text into the template.
This fix has the weakness that by removing the modifiers, I remove any other annotations as well.
Add another Action
I can add another named fix, to give me a choice when the alt+enter is used to display the QuickFix.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
- name: "Remove Disabled, keep other annotations, and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}\n\
{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
Here, I added an additional line in the new Quick Fix.
{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}
This takes the modifier list, encodes it as a string, then uses sed to remove the line with @Disabled from the string, but leaves all other lines in the modifier, i.e. it leaves all other annotations alone.
NOTE: Remember to add the "," in the sed, otherwise you will see a comment added to your preview. This is how Sensei alerts you to syntax errors in the sed command.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Nested sed calls
I was lucky that I could match both the @Disabled and @Test in a single search and replace.
If the code is more complicated and I wanted to have a sequence of sed commands then I can do that by nesting them:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
In the above example, I apply the @Test replacement to the results of applying the @Disabled replacement on the {{{ modifierList }}}.
Summary
sed is a very flexible way to achieve code rewriting and it is possible to nest the sed function calls for complicated rewrite conditions.
Recipes like this often end up being temporary because we are using them to improve our programming process, and once we have built up the muscle memory and no longer use the poor programming pattern we can remove or disable them in the Cookbook.
---
You can install Sensei from within IntelliJ using "Preferences \ Plugins" (Mac) or "Settings \ Plugins" (Windows) then just search for "sensei secure code".
All the code for this blog post can be found on GitHub in the `junitexamples` module of our blog examples repository https://github.com/SecureCodeWarrior/sensei-blog-examples

For this post, I've recreated a 'bad' coding approach that I used when I was learning JUnit, and will demonstrate how to convert the "bad'pattern to an agreed, and "better', coding pattern using Sensei.
When I was learning JUnit, I could only keep so much in my head at any one time. I constantly forgot how to skip tests when they were not working.
If we are working in a team then we can use code reviews on pull requests to help enforce coding styles. And we can shorten the feedback cycle when pair programming with a more experienced programmer.
We can also augment our process with tooling and have the tools prompt us to do the right thing. Thoughtworks described this as "tools over rules," in their Technology Radar listing for Sensei, to: "make it easy to do the right thing over applying checklist-like governance rules and procedures"
Disabling a JUnit Test
Ideally, I would, as we all know, use the @Disabled annotation and write:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
But, when learning, I had to train myself to use @Disabled.
When I forgot how to disable a Test method I would remove the @Test annotation and rename the test:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
It wasn't good, but it got the job done. I didn't have something like Sensei to help me remember and so I fell into using poor coding patterns.
The tasks I've taken on board for this post are to:
- Create a rule which finds methods that have been 'skipped' or 'disabled' by renaming the method.
- Create a QuickFix to rename the method and add both an @Test and @Disabled annotation.
Recipe Settings
The first step I take with Sensei is to "add new recipe" and search for the coding pattern I want the recipe to act on.
Name: JUnit: Make @Disabled @Test from SKIPTHIS
Short Description: Stop naming methods SKIPTHIS, use @Disabled @Test instead
And my search is very simple. I use a basic regex to match the method name.
search:
method:
name:
matches: "SKIPTHIS.*"

QuickFix Settings
The QuickFix is a little more complicated because it will rewrite the code, and I'll use a few steps to achieve my final code.
I want to:
- add an @Test annotation to the method
- add an @Disabled annotation to the method
- amend the method name
Adding the annotations is simple enough using the addAnnotation fix. If I use a fully qualified name for the annotation then Sensei will automatically add the imports for me.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
actions:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
The actual renaming seems a little more complicated but I'm just using a regex replacement, and the generic way to do this with Sensei is to use sed in a rewrite action.
Because the rewrite actions are Mustache templates, Sensei has some functional extensions in the template mechanism. A function is represented with {{#...}} so for sed the function is {{#sed}}. The function takes two comma-separated arguments.
The first argument is the sed statement:
- s/(.*) SKIPTHIS(.*)/$1 $2/
The second argument is the String to apply the sed statement to, which in this case is the method itself, and this is represented in the Mustache variables as:
- {{{.}}}
Giving me the rewrite action of:
- rewrite:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

The sed implementation requires that when the arguments themselves contain commas, they are wrapped with {{#encodeString}} and {{/encodeString}} - e.g. {{#encodeString}}{{{.}}}{{/encodeString}}
Reverse Recipe
Since this is an example, and we might want to use this in demos, I wanted to explore how to reverse out the above change using a Sensei recipe.
Thinking it through I want to find a method annotated with @Disabled but only in the class SkipThisTest where I do the demo:
Name: JUnit: demo in SkipThisTest remove @Disabled and revert to SKIPTHIS
Short Description: remove @Disabled and revert to SKIPTHIS for demo purposes in the project
Level: warning
The Recipe Settings Search is very simple, matching the annotation in a specific class.
search:
method:
annotation:
type: "Disabled"
in:
class:
name: "SkipThisTest"
To avoid making the code look like it is an error I defined the general setting on the recipe to be a Warning. Warnings are shown with highlights in the code and it doesn't make the code look like it has a major problem.
For the Quick fix, since we have matched the method, I use the rewrite action and populate the template using the variables.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
I add every variable except the modifier (since I want to get rid of the annotations) and add the SKIPTHIS text into the template.
This fix has the weakness that by removing the modifiers, I remove any other annotations as well.
Add another Action
I can add another named fix, to give me a choice when the alt+enter is used to display the QuickFix.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
- name: "Remove Disabled, keep other annotations, and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}\n\
{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
Here, I added an additional line in the new Quick Fix.
{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}
This takes the modifier list, encodes it as a string, then uses sed to remove the line with @Disabled from the string, but leaves all other lines in the modifier, i.e. it leaves all other annotations alone.
NOTE: Remember to add the "," in the sed, otherwise you will see a comment added to your preview. This is how Sensei alerts you to syntax errors in the sed command.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Nested sed calls
I was lucky that I could match both the @Disabled and @Test in a single search and replace.
If the code is more complicated and I wanted to have a sequence of sed commands then I can do that by nesting them:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
In the above example, I apply the @Test replacement to the results of applying the @Disabled replacement on the {{{ modifierList }}}.
Summary
sed is a very flexible way to achieve code rewriting and it is possible to nest the sed function calls for complicated rewrite conditions.
Recipes like this often end up being temporary because we are using them to improve our programming process, and once we have built up the muscle memory and no longer use the poor programming pattern we can remove or disable them in the Cookbook.
---
You can install Sensei from within IntelliJ using "Preferences \ Plugins" (Mac) or "Settings \ Plugins" (Windows) then just search for "sensei secure code".
All the code for this blog post can be found on GitHub in the `junitexamples` module of our blog examples repository https://github.com/SecureCodeWarrior/sensei-blog-examples

Click on the link below and download the PDF of this resource.
Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.
View reportBook a demoAlan Richardson has more than twenty years of professional IT experience, working as a developer and at every level of the testing hierarchy from Tester through to Head of Testing. Head of Developer Relations at Secure Code Warrior, he works directly with teams, to improve the development of quality secure code. Alan is the author of four books including “Dear Evil Tester”, and “Java For Testers”. Alan has also created online training courses to help people learn Technical Web Testing and Selenium WebDriver with Java. Alan posts his writing and training videos on SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, and CompendiumDev.co.uk.
For this post, I've recreated a 'bad' coding approach that I used when I was learning JUnit, and will demonstrate how to convert the "bad'pattern to an agreed, and "better', coding pattern using Sensei.
When I was learning JUnit, I could only keep so much in my head at any one time. I constantly forgot how to skip tests when they were not working.
If we are working in a team then we can use code reviews on pull requests to help enforce coding styles. And we can shorten the feedback cycle when pair programming with a more experienced programmer.
We can also augment our process with tooling and have the tools prompt us to do the right thing. Thoughtworks described this as "tools over rules," in their Technology Radar listing for Sensei, to: "make it easy to do the right thing over applying checklist-like governance rules and procedures"
Disabling a JUnit Test
Ideally, I would, as we all know, use the @Disabled annotation and write:
@Disabled
@Test
void canWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
But, when learning, I had to train myself to use @Disabled.
When I forgot how to disable a Test method I would remove the @Test annotation and rename the test:
class SkipThisTest {
void SKIPTHIScanWeAddTwoNumbers(){
Assertions.fail("this test was skipped and should not run");
}
}
It wasn't good, but it got the job done. I didn't have something like Sensei to help me remember and so I fell into using poor coding patterns.
The tasks I've taken on board for this post are to:
- Create a rule which finds methods that have been 'skipped' or 'disabled' by renaming the method.
- Create a QuickFix to rename the method and add both an @Test and @Disabled annotation.
Recipe Settings
The first step I take with Sensei is to "add new recipe" and search for the coding pattern I want the recipe to act on.
Name: JUnit: Make @Disabled @Test from SKIPTHIS
Short Description: Stop naming methods SKIPTHIS, use @Disabled @Test instead
And my search is very simple. I use a basic regex to match the method name.
search:
method:
name:
matches: "SKIPTHIS.*"

QuickFix Settings
The QuickFix is a little more complicated because it will rewrite the code, and I'll use a few steps to achieve my final code.
I want to:
- add an @Test annotation to the method
- add an @Disabled annotation to the method
- amend the method name
Adding the annotations is simple enough using the addAnnotation fix. If I use a fully qualified name for the annotation then Sensei will automatically add the imports for me.
availableFixes:
- name: "Add @Disabled and @Test Annotation"
actions:
- addAnnotation:
annotation: "@org.junit.jupiter.api.Test"
- addAnnotation:
annotation: "@org.junit.jupiter.api.Disabled"
The actual renaming seems a little more complicated but I'm just using a regex replacement, and the generic way to do this with Sensei is to use sed in a rewrite action.
Because the rewrite actions are Mustache templates, Sensei has some functional extensions in the template mechanism. A function is represented with {{#...}} so for sed the function is {{#sed}}. The function takes two comma-separated arguments.
The first argument is the sed statement:
- s/(.*) SKIPTHIS(.*)/$1 $2/
The second argument is the String to apply the sed statement to, which in this case is the method itself, and this is represented in the Mustache variables as:
- {{{.}}}
Giving me the rewrite action of:
- rewrite:
to: "{{#sed}}s/(.*) SKIPTHIS(.*)/$1 $2/,{{{.}}}{{/sed}}"

The sed implementation requires that when the arguments themselves contain commas, they are wrapped with {{#encodeString}} and {{/encodeString}} - e.g. {{#encodeString}}{{{.}}}{{/encodeString}}
Reverse Recipe
Since this is an example, and we might want to use this in demos, I wanted to explore how to reverse out the above change using a Sensei recipe.
Thinking it through I want to find a method annotated with @Disabled but only in the class SkipThisTest where I do the demo:
Name: JUnit: demo in SkipThisTest remove @Disabled and revert to SKIPTHIS
Short Description: remove @Disabled and revert to SKIPTHIS for demo purposes in the project
Level: warning
The Recipe Settings Search is very simple, matching the annotation in a specific class.
search:
method:
annotation:
type: "Disabled"
in:
class:
name: "SkipThisTest"
To avoid making the code look like it is an error I defined the general setting on the recipe to be a Warning. Warnings are shown with highlights in the code and it doesn't make the code look like it has a major problem.
For the Quick fix, since we have matched the method, I use the rewrite action and populate the template using the variables.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
I add every variable except the modifier (since I want to get rid of the annotations) and add the SKIPTHIS text into the template.
This fix has the weakness that by removing the modifiers, I remove any other annotations as well.
Add another Action
I can add another named fix, to give me a choice when the alt+enter is used to display the QuickFix.
availableFixes:
- name: "Remove Disabled and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
- name: "Remove Disabled, keep other annotations, and rename to SKIPTHIS..."
actions:
- rewrite:
to: "{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}\n\
{{{ returnTypeElement }}} SKIPTHIS{{{ nameIdentifier }}}{{{ parameterList\
\ }}}{{{ body }}}"
target: "self"
Here, I added an additional line in the new Quick Fix.
{{#sed}}s/(@Disabled\n.*@Test)//,{{{ modifierList }}}{{/sed}}
This takes the modifier list, encodes it as a string, then uses sed to remove the line with @Disabled from the string, but leaves all other lines in the modifier, i.e. it leaves all other annotations alone.
NOTE: Remember to add the "," in the sed, otherwise you will see a comment added to your preview. This is how Sensei alerts you to syntax errors in the sed command.
/* e.g: {{#sed}}s/all/world/,helloall{{/sed}} */
Nested sed calls
I was lucky that I could match both the @Disabled and @Test in a single search and replace.
If the code is more complicated and I wanted to have a sequence of sed commands then I can do that by nesting them:
{{#sed}}s/@Test//,{{#sed}}s/@Disabled\n//,{{{ modifierList }}}{{/sed}}{{/sed}}
In the above example, I apply the @Test replacement to the results of applying the @Disabled replacement on the {{{ modifierList }}}.
Summary
sed is a very flexible way to achieve code rewriting and it is possible to nest the sed function calls for complicated rewrite conditions.
Recipes like this often end up being temporary because we are using them to improve our programming process, and once we have built up the muscle memory and no longer use the poor programming pattern we can remove or disable them in the Cookbook.
---
You can install Sensei from within IntelliJ using "Preferences \ Plugins" (Mac) or "Settings \ Plugins" (Windows) then just search for "sensei secure code".
All the code for this blog post can be found on GitHub in the `junitexamples` module of our blog examples repository https://github.com/SecureCodeWarrior/sensei-blog-examples
Table of contents
Alan Richardson has more than twenty years of professional IT experience, working as a developer and at every level of the testing hierarchy from Tester through to Head of Testing. Head of Developer Relations at Secure Code Warrior, he works directly with teams, to improve the development of quality secure code. Alan is the author of four books including “Dear Evil Tester”, and “Java For Testers”. Alan has also created online training courses to help people learn Technical Web Testing and Selenium WebDriver with Java. Alan posts his writing and training videos on SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, and CompendiumDev.co.uk.

Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.
Book a demoDownloadResources to get you started
Secure by Design: Defining Best Practices, Enabling Developers and Benchmarking Preventative Security Outcomes
In this research paper, Secure Code Warrior co-founders, Pieter Danhieux and Dr. Matias Madou, Ph.D., along with expert contributors, Chris Inglis, Former US National Cyber Director (now Strategic Advisor to Paladin Capital Group), and Devin Lynch, Senior Director, Paladin Global Institute, will reveal key findings from over twenty in-depth interviews with enterprise security leaders including CISOs, a VP of Application Security, and software security professionals.
Benchmarking Security Skills: Streamlining Secure-by-Design in the Enterprise
Finding meaningful data on the success of Secure-by-Design initiatives is notoriously difficult. CISOs are often challenged when attempting to prove the return on investment (ROI) and business value of security program activities at both the people and company levels. Not to mention, it’s particularly difficult for enterprises to gain insights into how their organizations are benchmarked against current industry standards. The President’s National Cybersecurity Strategy challenged stakeholders to “embrace security and resilience by design.” The key to making Secure-by-Design initiatives work is not only giving developers the skills to ensure secure code, but also assuring the regulators that those skills are in place. In this presentation, we share a myriad of qualitative and quantitative data, derived from multiple primary sources, including internal data points collected from over 250,000 developers, data-driven customer insights, and public studies. Leveraging this aggregation of data points, we aim to communicate a vision of the current state of Secure-by-Design initiatives across multiple verticals. The report details why this space is currently underutilized, the significant impact a successful upskilling program can have on cybersecurity risk mitigation, and the potential to eliminate categories of vulnerabilities from a codebase.
Secure code training topics & content
Our industry-leading content is always evolving to fit the ever changing software development landscape with your role in mind. Topics covering everything from AI to XQuery Injection, offered for a variety of roles from Architects and Engineers to Product Managers and QA. Get a sneak peak of what our content catalog has to offer by topic and role.
Resources to get you started
Revealed: How the Cyber Industry Defines Secure by Design
In our latest white paper, our Co-Founders, Pieter Danhieux and Dr. Matias Madou, Ph.D., sat down with over twenty enterprise security leaders, including CISOs, AppSec leaders and security professionals, to figure out the key pieces of this puzzle and uncover the reality behind the Secure by Design movement. It’s a shared ambition across the security teams, but no shared playbook.
Is Vibe Coding Going to Turn Your Codebase Into a Frat Party?
Vibe coding is like a college frat party, and AI is the centerpiece of all the festivities, the keg. It’s a lot of fun to let loose, get creative, and see where your imagination can take you, but after a few keg stands, drinking (or, using AI) in moderation is undoubtedly the safer long-term solution.