From 8b13b8c556283d33bfc9e20733dbd159fcc3d6ac Mon Sep 17 00:00:00 2001 From: glelouet Date: Fri, 29 May 2026 20:13:59 +0200 Subject: [PATCH 1/9] adding explanations on how to test what. --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/README.md b/README.md index 3bc9d860..7ae71cf2 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,44 @@ For eclipse, a formatter xml and a cleanup xml are present in the meta/formatter NOTE : you also need to change the save actions to make them meet the clean up actions. Save actions are done even when they are not present in the clean up. +### Testing + +New features, as well as bug fixes, are expected to provide the minimum amount of test cases to ensure their main usage remains correct. +For example, if you find a bug in a specific case, then that specific case must be tested against in the PR fixing it. + +Disabling an existing test must be explained (typically no more relevant). + +There are three main ways to add tests, one for checking your own class behavior and the **generated file** content, one for checking the generated **class** content and behaviour, and the last for checking your plugin generator behavior. + +#### In the main module + +You can add usual unit tests in the [main module's test dir](./jcodemodel/src/test/java). + +Those are useful to check the behavior of specific parts of the projects, as well as the expected file content for a constructed JCM , typically using [test utils](./jcodemodel/src/test/java/com/helger/jcodemodel/util/CodeModelTestsHelper.java) + +Note that the helper class allows to compile a JCML in memory, however using the generated class can be cumbersome since you need to use reflect, unless you can cast it to a known interface. +The next method allows easier manipulation, plus it permits to visualy check the generated class files since they are exported and put in git. Therefore any actual change in generated files can be tracked. + +#### In the jcodemodeltests module + +[This module](./jcodemodeltests) uses a specific architecture : + +1. generating classes should be annotated with `@TestJCM` and contain public methods that have a JCM and/or a JPackage parameter(s), or produce their own JCM. The convention is to end such a class with `TestGen` and place them in their own feature package. The method can be static; if not, a new instance is generated for each generating method. +2. those classes are parsed during the generate-test phase and the resulting (or requested) JCM is then exported in the `src/generated/javatest` dir. You can run the [GenerateTestFiles](./jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java) in your IDE to generate them manually. +3. You can then add test classes in the usual `src/test/java` dir, that rely on those generated classes to check their behaviour and content. The convention is to place the test clas in the same package and with same start as the generating one, ending with `Test`. + +General convention is as such, for feature Feat : generat**ing** is `jcodemodel/tests/feat/FeatTestGen.java` ; generat**ed** should be named eg `jcodemodel/tests/feat/FeatExample1.java` ; **testing** class should be `jcodemodel/tests/feat/FeatTest.java` + +#### Testing your plugin's generator + +A plugin generator generates a JCM taht the plugin will export when requested. + +The generator module should be in the [./plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; +The testing module should be in the [./examples/plugins] submodule, with a module name starting with `XPL Generator ` . +Example are the [HelloWorld generator](./plugin/generators/helloworld) and its [HelloWorld example](./examples/plugins/helloworld) modules. + +The testing module should not rely on internet data, as this can be an issue when remote host is down. +With [correct configuration](./examples/plugins/helloworld/pom.xml) the plugin will apply the generator and produce the classes in `src/generated/java` , allowing the usual unit tests in that module. --- From 009daa8f76c0b1889535daa8d5f6f388443ff37f Mon Sep 17 00:00:00 2001 From: glelouet Date: Sun, 31 May 2026 17:26:04 +0200 Subject: [PATCH 2/9] moving the doc, changing the REAMDE, adding tutorial class in the test/ --- README.md | 71 ++------------ documentation/contributing.md | 61 ++++++++++++ documentation/starting.md | 93 +++++++++++++++++++ jcodemodel/src/test/java/JCMFirstProgram.java | 16 ++++ 4 files changed, 179 insertions(+), 62 deletions(-) create mode 100644 documentation/contributing.md create mode 100644 documentation/starting.md create mode 100644 jcodemodel/src/test/java/JCMFirstProgram.java diff --git a/README.md b/README.md index 7ae71cf2..c0884e36 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,20 @@ [![javadoc](https://javadoc.io/badge2/com.helger/jcodemodel/javadoc.svg)](https://javadoc.io/doc/com.helger/jcodemodel) -A fork of the com.sun.codemodel 2.7-SNAPSHOT. +This project provides modeling and exporting java source code at java runtime, either in a pre-processing phase or to acces them using a dynamic Classloader. + +It is a fork of the com.sun.codemodel 2.7-SNAPSHOT. + The classes in this project use a different package name `com.helger.jcodemodel` to avoid conflicts with other `com.sun.codemodel` instances that might be floating around in the classpath. That of course implies, that this artefact cannot directly be used with JAXB, since the configuration of this would be very tricky. -A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. is available. +## Links and doc + + - A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. is available. + - This project has a dedicated [documentation folder](./documentation) maintained by helpers. Don't hesitate [to help](documentation/contributing.md) ! + ## Maven usage @@ -200,66 +207,6 @@ v2.6.4 - 2014-04-10 2013-09-23 * Changes from https://github.com/UnquietCode/JCodeModel have been incorporated. -## Contribution - -Pull requests must follow my personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) - -### Tabs vs spaces - -This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](sh/tabspaces) makes that chnage, run it from the root project. - - -What this script does : - - - create the file .git/info/attributes with `*.java filter=tabspace` . This will tell git to apply the script tabspace on the *.java files - - run `git config filter.tabspace.clean 'expand --tabs=2 --initial'` to ask git to replace tabs with two spaces on commit of *.java files. - - run `git config filter.tabspace.smudge 'unexpand --tabs=2 --first-only'` to request git to replace double spaces with two tabs on checking a *.java file out. - - -### Eclipse - -For eclipse, a formatter xml and a cleanup xml are present in the meta/formatter/eclipse/ directory. You can load them from the "project properties > java code style" settings. Check "Enable project specific settings", then load them. - -NOTE : you also need to change the save actions to make them meet the clean up actions. Save actions are done even when they are not present in the clean up. - -### Testing - -New features, as well as bug fixes, are expected to provide the minimum amount of test cases to ensure their main usage remains correct. -For example, if you find a bug in a specific case, then that specific case must be tested against in the PR fixing it. - -Disabling an existing test must be explained (typically no more relevant). - -There are three main ways to add tests, one for checking your own class behavior and the **generated file** content, one for checking the generated **class** content and behaviour, and the last for checking your plugin generator behavior. - -#### In the main module - -You can add usual unit tests in the [main module's test dir](./jcodemodel/src/test/java). - -Those are useful to check the behavior of specific parts of the projects, as well as the expected file content for a constructed JCM , typically using [test utils](./jcodemodel/src/test/java/com/helger/jcodemodel/util/CodeModelTestsHelper.java) - -Note that the helper class allows to compile a JCML in memory, however using the generated class can be cumbersome since you need to use reflect, unless you can cast it to a known interface. -The next method allows easier manipulation, plus it permits to visualy check the generated class files since they are exported and put in git. Therefore any actual change in generated files can be tracked. - -#### In the jcodemodeltests module - -[This module](./jcodemodeltests) uses a specific architecture : - -1. generating classes should be annotated with `@TestJCM` and contain public methods that have a JCM and/or a JPackage parameter(s), or produce their own JCM. The convention is to end such a class with `TestGen` and place them in their own feature package. The method can be static; if not, a new instance is generated for each generating method. -2. those classes are parsed during the generate-test phase and the resulting (or requested) JCM is then exported in the `src/generated/javatest` dir. You can run the [GenerateTestFiles](./jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java) in your IDE to generate them manually. -3. You can then add test classes in the usual `src/test/java` dir, that rely on those generated classes to check their behaviour and content. The convention is to place the test clas in the same package and with same start as the generating one, ending with `Test`. - -General convention is as such, for feature Feat : generat**ing** is `jcodemodel/tests/feat/FeatTestGen.java` ; generat**ed** should be named eg `jcodemodel/tests/feat/FeatExample1.java` ; **testing** class should be `jcodemodel/tests/feat/FeatTest.java` - -#### Testing your plugin's generator - -A plugin generator generates a JCM taht the plugin will export when requested. - -The generator module should be in the [./plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; -The testing module should be in the [./examples/plugins] submodule, with a module name starting with `XPL Generator ` . -Example are the [HelloWorld generator](./plugin/generators/helloworld) and its [HelloWorld example](./examples/plugins/helloworld) modules. - -The testing module should not rely on internet data, as this can be an issue when remote host is down. -With [correct configuration](./examples/plugins/helloworld/pom.xml) the plugin will apply the generator and produce the classes in `src/generated/java` , allowing the usual unit tests in that module. --- diff --git a/documentation/contributing.md b/documentation/contributing.md new file mode 100644 index 00000000..afe996b0 --- /dev/null +++ b/documentation/contributing.md @@ -0,0 +1,61 @@ +## Contributing + +Pull requests must follow my personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) + +### Tabs vs spaces + +This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](../sh/tabspaces) makes that change, run it from the root project. + + +What this script does : + + - create the file .git/info/attributes with `*.java filter=tabspace` . This will tell git to apply the script tabspace on the *.java files + - run `git config filter.tabspace.clean 'expand --tabs=2 --initial'` to ask git to replace tabs with two spaces on commit of *.java files. + - run `git config filter.tabspace.smudge 'unexpand --tabs=2 --first-only'` to request git to replace double spaces with tabs when checking a *.java file out. + + +### Eclipse + +For eclipse, a formatter xml and a cleanup xml are present in the meta/formatter/eclipse/ directory. You can load them from the "project properties > java code style" settings. Check "Enable project specific settings", then load them. + +NOTE : you also need to change the save actions to make them meet the clean up actions. Save actions are done even when they are not present in the clean up. + +### Testing + +New features, as well as bug fixes, are expected to provide the minimum amount of test cases to ensure their main usage remains correct. +For example, if you find a bug in a specific case, then that specific case must be tested against in the PR fixing it. + +Disabling an existing test must be explained (typically no more relevant), at least in the commit or in the PR. + +There are three main ways to add tests, one for checking your own class behavior and the **generated file** content, one for checking the generated **class** content and behaviour, and the last for checking your plugin generator behavior. + +#### In the main module + +You can add usual unit tests in the [main module's test dir](../jcodemodel/src/test/java). + +Those are useful to check the behavior of specific parts of the projects, as well as the expected file content for a constructed JCM , typically using [test utils](../jcodemodel/src/test/java/com/helger/jcodemodel/util/CodeModelTestsHelper.java) + +Note that the helper class allows to compile a JCML in memory, however using the generated class can be cumbersome since you need to use reflect, unless you can cast it to a known interface. +The next method allows easier manipulation, plus it permits to visualy check the generated class files since they are exported and put in git. Therefore any actual change in generated files can be tracked. + +#### In the jcodemodeltests module + +[This module](./jcodemodeltests) uses a specific architecture : + +1. generating classes should be annotated with `@TestJCM` and contain public methods that have a JCM and/or a JPackage parameter(s), or produce their own JCM. The convention is to end such a class with `TestGen` and place them in their own feature package. The method can be static; if not, a new instance is generated for each generating method. +2. those classes are parsed during the generate-test phase and the resulting (or requested) JCM is then exported in the `src/generated/javatest` dir. You can run the [GenerateTestFiles](../jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java) in your IDE to generate them manually. +3. You can then add test classes in the usual `src/test/java` dir, that rely on those generated classes to check their behaviour and content. The convention is to place the test clas in the same package and with same start as the generating one, ending with `Test`. + +General convention is as such, for feature Feat : generat**ing** is `jcodemodel/tests/feat/FeatTestGen.java` ; generat**ed** should be named eg `jcodemodel/tests/feat/FeatExample1.java` ; **testing** class should be `jcodemodel/tests/feat/FeatTest.java` + +#### Testing your plugin's generator + +A generator generates a JCM that the plugin will export when requested. + + - The generator module should be in the [./plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; + - The testing module should be in the [./examples/plugins] submodule, with a module name starting with `XPL Generator ` . + +For example, the [HelloWorld generator](../plugin/generators/helloworld/pom.xml) and its [HelloWorld example](../examples/plugins/helloworld/pom.xml) modules. + +The testing module should not rely on internet data, as this can be an issue when remote host is down. +With [correct configuration](../examples/plugins/helloworld/pom.xml) the plugin will apply the generator and produce the classes in `src/generated/java` , allowing the usual unit tests in that module. \ No newline at end of file diff --git a/documentation/starting.md b/documentation/starting.md new file mode 100644 index 00000000..2d93c9cf --- /dev/null +++ b/documentation/starting.md @@ -0,0 +1,93 @@ +## Starting with JCodeModel (JCM) + +Before starting, one must now what it can do : JCM is made to generate java code, pre-compiling or at runtime, by a running java program. + +### Requirements + +Starting requires a Java Development Kit (JDK) at least version 17, maven v3 minimum installed. We strongly recommend an IDE ; and git to manage your code base. + +#### Windows + +Several links to help you get them : + + - [Java](https://www.java.com/download/manual.jsp) + - [Maven](https://maven.apache.org/download.cgi) + - [NetBeans IDE](https://netbeans.apache.org/front/main/download/) + - [Git](https://git-scm.com/install/windows) + +Note that the Git for windows also embeds a BASH which is very useful for running linux scripts on windows. + +#### Linux + +Those are pretty standard. For example Ubuntu can install them with `sudo apt install default-jdk maven netbeans git-all` + +#### Maven project setup + +Once you have a java project loaded in your IDE, you need to add a dependency to JCM. This is done typically with the following lines in your root pom.xml : + +```xml + + + + com.helger + jcodemodel + ${jcodemodel.version} + +``` + +You then need to replace  `${jcodemodel.version}` by the version you intend to use ; +OR set it as a property (better) typically with + +```xml + + + x.y.z +``` + +OR even (recommended) you remove the version line completely and instead import the JCM pom with + + +```xml + + + + + com.helger + jcodemodel-parent-pom + x.y.z + import + pom + + + + + com.helger + jcodemodel + +``` + +### First program + +Let's first make a simple program that generates a new, empty class. With java 25 you can create a fast class `JCMFirstProgram` containing + +```java +void main() throws JCodeModelException, IOException { + var jcm = new JCodeModel(); + jcm._class("JCMFirstClass"); + new JCMWriter(jcm) + .build(new File(".")); +} +``` + +Then let your IDE resolve the names for you. + +If you are using java <25 then you need to use a full class. We made [one already](../jcodemodel/src/test/java/JCMFirstProgram.java) + +Let's explain the instructions + + - `var jcm = new JCodeModel();` We need to create a model to represent the classes we want to export. JCodeModel is the class for that model. + - `jcm._class("JCMFirstClass");` We add a new class in that model. This is a public class by default. + - `new JCMWriter(jcm)` we need a writer to write down the model we just created. This allows us to provide exporting options. + - `.build(new File("."));` write the model we created to the local directory. + + \ No newline at end of file diff --git a/jcodemodel/src/test/java/JCMFirstProgram.java b/jcodemodel/src/test/java/JCMFirstProgram.java new file mode 100644 index 00000000..9b834396 --- /dev/null +++ b/jcodemodel/src/test/java/JCMFirstProgram.java @@ -0,0 +1,16 @@ +import java.io.File; +import java.io.IOException; + +import com.helger.jcodemodel.JCodeModel; +import com.helger.jcodemodel.exceptions.JCodeModelException; +import com.helger.jcodemodel.writer.JCMWriter; + +public class JCMFirstProgram { + + public static void main(String... args) throws JCodeModelException, IOException { + var jcm = new JCodeModel(); + jcm._class("JCMFirstClass"); + new JCMWriter(jcm).build(new File(".")); + } + +} From ccf7a0c1210e80a35e6b7e91156183cf71604f3c Mon Sep 17 00:00:00 2001 From: glelouet Date: Sun, 31 May 2026 17:28:32 +0200 Subject: [PATCH 3/9] mv documentation docs --- README.md | 2 +- {documentation => docs}/contributing.md | 0 {documentation => docs}/starting.md | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename {documentation => docs}/contributing.md (100%) rename {documentation => docs}/starting.md (100%) diff --git a/README.md b/README.md index c0884e36..9be76d5d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ this would be very tricky. ## Links and doc - A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. is available. - - This project has a dedicated [documentation folder](./documentation) maintained by helpers. Don't hesitate [to help](documentation/contributing.md) ! + - This project has a dedicated [documentation folder](./docs) maintained by helpers. Don't hesitate [to help](documentation/contributing.md) ! ## Maven usage diff --git a/documentation/contributing.md b/docs/contributing.md similarity index 100% rename from documentation/contributing.md rename to docs/contributing.md diff --git a/documentation/starting.md b/docs/starting.md similarity index 100% rename from documentation/starting.md rename to docs/starting.md From bf32ebeec49c6a40ef0131868a2ae9b3896eb4b1 Mon Sep 17 00:00:00 2001 From: glelouet Date: Sun, 31 May 2026 20:54:50 +0200 Subject: [PATCH 4/9] typos, plus reworked the starting to go deeper the rabbit hole. --- README.md | 2 +- docs/contributing.md | 27 ++++-- docs/extending.md | 5 + docs/overview.md | 9 ++ docs/starting.md | 91 +++++++++++++++++-- jcodemodel/.gitignore | 1 + jcodemodel/src/test/java/JCMFirstProgram.java | 4 +- 7 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 docs/extending.md create mode 100644 docs/overview.md create mode 100644 jcodemodel/.gitignore diff --git a/README.md b/README.md index 9be76d5d..81842996 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ this would be very tricky. ## Links and doc - A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. is available. - - This project has a dedicated [documentation folder](./docs) maintained by helpers. Don't hesitate [to help](documentation/contributing.md) ! + - This project has a dedicated [documentation folder](./docs) maintained by helpers. Don't hesitate [to help](./docs/contributing.md) ! ## Maven usage diff --git a/docs/contributing.md b/docs/contributing.md index afe996b0..e6f5ccc3 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,8 +1,10 @@ ## Contributing +### Formatting + Pull requests must follow my personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) -### Tabs vs spaces +#### Tabs vs spaces This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](../sh/tabspaces) makes that change, run it from the root project. @@ -14,20 +16,25 @@ What this script does : - run `git config filter.tabspace.smudge 'unexpand --tabs=2 --first-only'` to request git to replace double spaces with tabs when checking a *.java file out. -### Eclipse +#### Eclipse For eclipse, a formatter xml and a cleanup xml are present in the meta/formatter/eclipse/ directory. You can load them from the "project properties > java code style" settings. Check "Enable project specific settings", then load them. NOTE : you also need to change the save actions to make them meet the clean up actions. Save actions are done even when they are not present in the clean up. + ### Testing -New features, as well as bug fixes, are expected to provide the minimum amount of test cases to ensure their main usage remains correct. +New features, as well as bug fixes, are expected to test the minimum amount of use cases to ensure their main usage remains correct. For example, if you find a bug in a specific case, then that specific case must be tested against in the PR fixing it. +This is important both for validating your PR, but also to ensure new modifications won't break the existing features Disabling an existing test must be explained (typically no more relevant), at least in the commit or in the PR. -There are three main ways to add tests, one for checking your own class behavior and the **generated file** content, one for checking the generated **class** content and behaviour, and the last for checking your plugin generator behavior. +There are three main ways to add tests : + - checking your own class behavior and the generated **file** content, + - checking the generated **class** content and behavior, + - checking your plugin generator behavior. #### In the main module @@ -35,12 +42,14 @@ You can add usual unit tests in the [main module's test dir](../jcodemodel/src/t Those are useful to check the behavior of specific parts of the projects, as well as the expected file content for a constructed JCM , typically using [test utils](../jcodemodel/src/test/java/com/helger/jcodemodel/util/CodeModelTestsHelper.java) -Note that the helper class allows to compile a JCML in memory, however using the generated class can be cumbersome since you need to use reflect, unless you can cast it to a known interface. -The next method allows easier manipulation, plus it permits to visualy check the generated class files since they are exported and put in git. Therefore any actual change in generated files can be tracked. +Implementation of parsers, validations, a well as code generation that does not persist at runtime (like javadocs, formatting, etc.) are expected to use this method. + +Note that the helper class allows to compile a JCM in memory, however using the generated class can be cumbersome since you need to use reflect, unless you can cast it to a known interface. +The next method allows easier manipulation, plus it permits to visually check the generated class files since they are exported and put in git. Therefore any later change in generated files can be tracked down to its commit. #### In the jcodemodeltests module -[This module](./jcodemodeltests) uses a specific architecture : +[This module](../jcodemodeltests) uses a specific architecture : 1. generating classes should be annotated with `@TestJCM` and contain public methods that have a JCM and/or a JPackage parameter(s), or produce their own JCM. The convention is to end such a class with `TestGen` and place them in their own feature package. The method can be static; if not, a new instance is generated for each generating method. 2. those classes are parsed during the generate-test phase and the resulting (or requested) JCM is then exported in the `src/generated/javatest` dir. You can run the [GenerateTestFiles](../jcodemodeltests/src/main/java/com/helger/jcodemodel/compile/annotation/GenerateTestFiles.java) in your IDE to generate them manually. @@ -52,8 +61,8 @@ General convention is as such, for feature Feat : generat**ing** is `jcodemodel/ A generator generates a JCM that the plugin will export when requested. - - The generator module should be in the [./plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; - - The testing module should be in the [./examples/plugins] submodule, with a module name starting with `XPL Generator ` . + - The generator module should be in the [../plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; + - The testing module should be in the [../examples/plugins] submodule, with a module name starting with `XPL Generator ` . For example, the [HelloWorld generator](../plugin/generators/helloworld/pom.xml) and its [HelloWorld example](../examples/plugins/helloworld/pom.xml) modules. diff --git a/docs/extending.md b/docs/extending.md new file mode 100644 index 00000000..9f60d743 --- /dev/null +++ b/docs/extending.md @@ -0,0 +1,5 @@ +## Extending JCM with plugin generator + +### Main maven plugin + +### Creating a generator \ No newline at end of file diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 00000000..88ae0826 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,9 @@ +## Project overview + +### Maven architecture + + + +### Core classes + +### Scripts \ No newline at end of file diff --git a/docs/starting.md b/docs/starting.md index 2d93c9cf..488489d1 100644 --- a/docs/starting.md +++ b/docs/starting.md @@ -4,7 +4,9 @@ Before starting, one must now what it can do : JCM is made to generate java code ### Requirements -Starting requires a Java Development Kit (JDK) at least version 17, maven v3 minimum installed. We strongly recommend an IDE ; and git to manage your code base. +Starting requires a Java Development Kit (JDK) at least version 17, maven v3 minimum installed. We strongly recommend an IDE ; and git is always a good idea to manage your code base. + +Note that Git for windows also embeds a Bash which is required for running the linux scripts on windows. However, if you don't intend to use the scripts nor to manage your codebase testing) then this is not mandatory. #### Windows @@ -15,8 +17,6 @@ Several links to help you get them : - [NetBeans IDE](https://netbeans.apache.org/front/main/download/) - [Git](https://git-scm.com/install/windows) -Note that the Git for windows also embeds a BASH which is very useful for running linux scripts on windows. - #### Linux Those are pretty standard. For example Ubuntu can install them with `sudo apt install default-jdk maven netbeans git-all` @@ -74,12 +74,13 @@ Let's first make a simple program that generates a new, empty class. With java 2 void main() throws JCodeModelException, IOException { var jcm = new JCodeModel(); jcm._class("JCMFirstClass"); - new JCMWriter(jcm) - .build(new File(".")); + File outFile = new File("src/generated/java/"); + outFile.mkdirs(); + new JCMWriter(jcm).build(outFile); } ``` -Then let your IDE resolve the names for you. +Then ask your IDE resolve the names for you. This should add imports at the top of the file If you are using java <25 then you need to use a full class. We made [one already](../jcodemodel/src/test/java/JCMFirstProgram.java) @@ -87,7 +88,81 @@ Let's explain the instructions - `var jcm = new JCodeModel();` We need to create a model to represent the classes we want to export. JCodeModel is the class for that model. - `jcm._class("JCMFirstClass");` We add a new class in that model. This is a public class by default. + - `File outFile = new File("src/generated/java/");` we need a directory to export the model. We Choose `src/generated/java` as source files and generated files should be in distinct directories. + - `outFile.mkdirs();` create the directory if it does not exist. - `new JCMWriter(jcm)` we need a writer to write down the model we just created. This allows us to provide exporting options. - - `.build(new File("."));` write the model we created to the local directory. + - `.build(outFile);` write the model we created to the specified directory. + +### Generating code for a library + +Now that you have a main class that produces code, you may want to embed that code in your program. However, the maven building is made in specific steps, and you can't easily compile the same source class and execute it. Instead, you need to have two maven modules, with the first one generating classes, and the second one, **core**, having the first one as dependency and calling its main class. + +It's actually possible to have maven do two passes of compiling but this is a bad habit as it blurs the visibility of what is generated, embedded, and can lead to issues with non-deterministic approaches. see [stackoverflow](https://stackoverflow.com/questions/21342342/run-maven-compilation-twice) + +#### Regorganising the maven project + +1. You need to change your **root** module to a `pom` module (in your root `pom.xml`) , that is an aggregation of other modules. This is the case, for example, for our [root module](../pom.xml) . Note that this means, the root module can't export java code by itself. Regardless, this is a good habit for maven projects, with your root module defining all the dependencies, properties, plugins, etc. . +2. Then you need one **generator** sub module in that root pom to have the class generation. This module will have the java class that we made previously. +3. Your **core** module will have the generating module as a dependency, with scope `optional` ; and a configuration of the `exec-maven-plugin` to call your java main class +4. You also need to tell maven that the `src/generated/java` dir of the **core** module is a source directory + +Your **core** pom.xml should now contain : - \ No newline at end of file + +```xml + + + + my.project + CodeGenerator + ${project.version} + true + +… + + + + org.codehaus.mojo + exec-maven-plugin + + + generate-classes + generate-sources + + java + + + + + JCMFirstProgram + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + src/generated/java + + + + + +``` + +Now, since your **generator** module is not configured to use its `src/generated/java` dir, you can run your main class in your IDE to check the result - but the generated class won't be visible in your **core**, until maven is used to rebuild the project. + +### Using the JCM plugin with an existing generator + +You can use the JCM plugin, by specifying its generator as dependency and the generator configuration. A generator is basically a parser of a resource into a JCM ; the JCM plugin [when called](../plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java#L105) selects the generator, configures it, generates the JCM, and exports it. + +For example, the CSV generator is used [in our examples](../examples/plugins/csv/pom.xml) to generate java source files from either a local file, and/or a complete configuration in the plugin. There are several configurations because there are several features to tests, you don't need that many. + +Note that it's possible to use an internet resource for the generator, but doing so should not be bound to a maven phase as a failure with the distant server could lead to building errors. diff --git a/jcodemodel/.gitignore b/jcodemodel/.gitignore new file mode 100644 index 00000000..21dd9913 --- /dev/null +++ b/jcodemodel/.gitignore @@ -0,0 +1 @@ +src/generated/java/JCMFirstClass.java diff --git a/jcodemodel/src/test/java/JCMFirstProgram.java b/jcodemodel/src/test/java/JCMFirstProgram.java index 9b834396..c6146d80 100644 --- a/jcodemodel/src/test/java/JCMFirstProgram.java +++ b/jcodemodel/src/test/java/JCMFirstProgram.java @@ -10,7 +10,9 @@ public class JCMFirstProgram { public static void main(String... args) throws JCodeModelException, IOException { var jcm = new JCodeModel(); jcm._class("JCMFirstClass"); - new JCMWriter(jcm).build(new File(".")); + File outFile = new File("src/generated/java/"); + outFile.mkdirs(); + new JCMWriter(jcm).build(outFile); } } From 7f4c0d6deaa0f26afd52033da6ccc65e085f9e29 Mon Sep 17 00:00:00 2001 From: glelouet Date: Tue, 2 Jun 2026 18:48:37 +0200 Subject: [PATCH 5/9] pass on starting --- docs/starting.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/starting.md b/docs/starting.md index 488489d1..392c8c57 100644 --- a/docs/starting.md +++ b/docs/starting.md @@ -1,12 +1,14 @@ ## Starting with JCodeModel (JCM) -Before starting, one must now what it can do : JCM is made to generate java code, pre-compiling or at runtime, by a running java program. +JCM at its core generates java source code, with the ability to do so at runtime and loaded the generated code, by a running java program. + +It can be used to generate data structures used to parse files or resources, create database entities, load runtime information and validate against meta data. ### Requirements -Starting requires a Java Development Kit (JDK) at least version 17, maven v3 minimum installed. We strongly recommend an IDE ; and git is always a good idea to manage your code base. +Starting requirements are : a Java Development Kit (JDK) at least version 17 ; maven v3 minimum installed. We strongly recommend an IDE ; and git is always a good idea to manage your code base. -Note that Git for windows also embeds a Bash which is required for running the linux scripts on windows. However, if you don't intend to use the scripts nor to manage your codebase testing) then this is not mandatory. +Note that Git for windows also embeds a Bash which is required for running the linux scripts on windows. However, if you don't intend to either use the scripts nor manage your codebase then this is not mandatory. For example, quick testing does not require git. #### Windows @@ -21,7 +23,7 @@ Several links to help you get them : Those are pretty standard. For example Ubuntu can install them with `sudo apt install default-jdk maven netbeans git-all` -#### Maven project setup +### Maven project setup Once you have a java project loaded in your IDE, you need to add a dependency to JCM. This is done typically with the following lines in your root pom.xml : @@ -68,7 +70,7 @@ OR even (recommended) you remove the version line completely and instead import ### First program -Let's first make a simple program that generates a new, empty class. With java 25 you can create a fast class `JCMFirstProgram` containing +Let's first make a simple program that generates a new, empty class. With [java 25](https://openjdk.org/jeps/445) you can create a file `JCMFirstProgram.java` containing only ```java void main() throws JCodeModelException, IOException { @@ -82,7 +84,7 @@ void main() throws JCodeModelException, IOException { Then ask your IDE resolve the names for you. This should add imports at the top of the file -If you are using java <25 then you need to use a full class. We made [one already](../jcodemodel/src/test/java/JCMFirstProgram.java) +If you are using java <25 then you need to use a full class. We made [one already](../jcodemodel/src/test/java/JCMFirstProgram.java) that contains those lines. Let's explain the instructions @@ -97,12 +99,12 @@ Let's explain the instructions Now that you have a main class that produces code, you may want to embed that code in your program. However, the maven building is made in specific steps, and you can't easily compile the same source class and execute it. Instead, you need to have two maven modules, with the first one generating classes, and the second one, **core**, having the first one as dependency and calling its main class. -It's actually possible to have maven do two passes of compiling but this is a bad habit as it blurs the visibility of what is generated, embedded, and can lead to issues with non-deterministic approaches. see [stackoverflow](https://stackoverflow.com/questions/21342342/run-maven-compilation-twice) +It's actually possible to have maven do two passes of compiling but this is a bad habit as it blurs the visibility of what is generated, embedded, and can lead to issues with non-deterministic approaches. See [stackoverflow](https://stackoverflow.com/questions/21342342/run-maven-compilation-twice) #### Regorganising the maven project -1. You need to change your **root** module to a `pom` module (in your root `pom.xml`) , that is an aggregation of other modules. This is the case, for example, for our [root module](../pom.xml) . Note that this means, the root module can't export java code by itself. Regardless, this is a good habit for maven projects, with your root module defining all the dependencies, properties, plugins, etc. . -2. Then you need one **generator** sub module in that root pom to have the class generation. This module will have the java class that we made previously. +1. You need to change your **root** module to a `pom` *packaging* (in your root `pom.xml`). This means, your root pom becomes an aggregation of other modules. This is the case, for example, for our [root module](../pom.xml) . Note that the root module can't anymore export java code by itself. Regardless, this is a good habit for maven projects, with your root module defining all the dependencies, properties, plugins, etc. . +2. You need one **generator** sub module in that root pom to have the class generation. This module will have the java class that we made previously. 3. Your **core** module will have the generating module as a dependency, with scope `optional` ; and a configuration of the `exec-maven-plugin` to call your java main class 4. You also need to tell maven that the `src/generated/java` dir of the **core** module is a source directory From 9089709cbc3966f32dab3a1583f4f08ddfb58556 Mon Sep 17 00:00:00 2001 From: glelouet Date: Tue, 2 Jun 2026 20:26:14 +0200 Subject: [PATCH 6/9] pass on contributing --- docs/contributing.md | 10 ++++++++++ docs/starting.md | 2 ++ 2 files changed, 12 insertions(+) diff --git a/docs/contributing.md b/docs/contributing.md index e6f5ccc3..cab2a4df 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,5 +1,15 @@ ## Contributing +The target audience is people who use JCM already + +If you use JCM, you may come across bugs, have ideas to implement, request features that could help you, or help implement or resolve issues. + +The ideas and requests should go to the [git's discussion](https://github.com/phax/jcodemodel/discussions) . They can then be converted to issues. + +Any bug should go in the [git's issues](https://github.com/phax/jcodemodel/issues) . They are then open for solving. Please provide a minimal working example, so that we can reproduce and check that the verification passes ; also mention what you are working on to avoid multiple person doing the same work. + +To help resolve an issue, you can [clone](https://github.com/phax/jcodemodel/fork) the repository, create a new branch, commit your changes, then submit a pull request, explaining what are the choices you made for that issue. + ### Formatting Pull requests must follow my personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) diff --git a/docs/starting.md b/docs/starting.md index 392c8c57..c68c3902 100644 --- a/docs/starting.md +++ b/docs/starting.md @@ -1,5 +1,7 @@ ## Starting with JCodeModel (JCM) +The target audience is developers who intend to use JCM as a part of their production. + JCM at its core generates java source code, with the ability to do so at runtime and loaded the generated code, by a running java program. It can be used to generate data structures used to parse files or resources, create database entities, load runtime information and validate against meta data. From b38be43f67c56f4969de3c513cda02d6b8c564aa Mon Sep 17 00:00:00 2001 From: glelouet Date: Thu, 4 Jun 2026 20:30:58 +0200 Subject: [PATCH 7/9] doc on extending/overview --- docs/extending.md | 59 +++++++++++++++++++++++++++++++++++++++++++++-- docs/overview.md | 28 +++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/docs/extending.md b/docs/extending.md index 9f60d743..0f024231 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1,5 +1,60 @@ ## Extending JCM with plugin generator -### Main maven plugin +### JCodeModel maven plugin -### Creating a generator \ No newline at end of file +The plugin is part of the project. However it does not generate data by itself, it needs to be specified a generator. For example, the [helloworld plugin example](../examples/plugins/helloworld/pom.xml) extensively configures that plugin in various ways. + +The [plugin](../plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/GenerateSourceMojo.java) does much of the leg-work to load a configured resource, load the configured generator - or default one if none is specified but present as dependency of the plugin - then call that generator and export the produced JCodeModel into a target directory. + +It contains several generic settings that can be used when generating the data. For example, the root package of all classes, the target directory, the source to load. +Any more genrator-specific configuration can be passed as the `params` plugin configuration. For example, in the HelloWorld example, + +```xml + + com.helger.jcodemodel.plugin.generators.helloworld.HelloWorldGenerator2 + src/generated/java2 + + Hello2 + world2 + + +``` + +forces a specific generator (instead of the default one provided by the HelloWorld Generator) ; then sets the output to be specific one (instead of default `src/generated/java`) ; then transmits the map `name=Hello2, value=world2` to the generator when the plugin is called. + +### Creating a generator + +To create a new Generator, you must +1. create a new project in the the `plugin/generators` directory +2. add it to the [generators pom](../plugin/generators/pom.xml) modules list +3. create a class that implements `ICodeModelBuilder` and is annotated with `@JCMGen` +4. implement your generator logic in the `void build (JCodeModel model, @Nullable InputStream source) throws JCodeModelException` method. +5. if needed, specify how it's configured by overriding the `void configure (@NonNull final Map params)` method + +The [annotation processor](../plugin/plugin/src/main/java/com/helger/jcodemodel/plugin/maven/generators/JCMGenProcessor.java) will automatically generate the resources required by the plugin on the maven install phase. + +You still need to test your generator, to be sure nothing changes too much + +### Testing a generator + +Once the generator module is done, you create a new project in the `examples/plugins` module, add it to the [plugin examples](../examples/plugins/pom.xml) modules list, and add your invocation of the plugin, with the generator as its dependency. + +This would be something like + +```xml + + + + + com.helger.jcodemodel + jcodemodel-maven-plugin + + + com.helger.jcodemodel.plugin.generators + mygenerator + ${project.version} + + +``` + +several executions can be configured, with various generators and/or configurations. \ No newline at end of file diff --git a/docs/overview.md b/docs/overview.md index 88ae0826..ae98118f 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -2,8 +2,34 @@ ### Maven architecture +The project is split in + - The [root pom project](../pom.xml) + - The [core project](../jcodemodel/pom.xml) lib to generate classes and resources programmatically. + - The [test project](../jccodemodeltests/pom.xml) validates the *generated* classes behavior. + - The [plugin](../plugin//plugin/pom.xml) to generate java classes in maven + - The various [plugin generators](../plugin/generators/pom.xml) to load a JCodeModel in the plugin + - The [examples](../examples/pom.xml) that showcase how to use JCodeModel, the plugin, the generators. + - The [beta](../beta/pom.xml) contains projects that may be merged into the core, or other modules, but could also be discarded entirely. ### Core classes -### Scripts \ No newline at end of file +#### JCodeModel + +This is the main class. It contains the definition of the classes and resources to generate. + +Its main usage is to add classes using the various `_class` methods. Those classes can then be added methods, fields, or other classes. + +#### JCMWriter + +This allows to export a `JCodeModel`. Typically to a directory. + +### Scripts + +The scripts present in the [sh directory](../sh) are run using a linux shell. For windows, you rather install git for windows which comes with a `bash` shell. + + - [cleaninstall](../sh/cleaninstall) runs the maven up-to install phases with parrallel execution and no output of the transfer to reduce logs, with a call to the clean phase to delete all intermediate products. It's only useful when you need to ensure other branches don't interfere with the result, like before a release. + - [install](../sh/install) does it without a clean. That's the main call to typically test changes. + - [mergeupstream](../sh/mergeupstream) adds an `upstream` repository to you local git, if needed, then checks its `master` commits out in the current branch. This allows to have your local branch up-to-date, for example before submitting a PR. + - [upgrades](../sh/upgrades) lists the possible dependencies/plugins upgrades. This is purely informative. + - [voidtest](../sh/voidtest) compiles and run the project, up to the integration-test phase, on a fresh (empty, temporary) maven repository. This will force re-downloading of **all** the libraries and plugins. This is only used when we suspect compiled libraries are generating issues. \ No newline at end of file From 6afb98e961c82b91b768ff998333e9afb512c34f Mon Sep 17 00:00:00 2001 From: glelouet Date: Sat, 6 Jun 2026 23:20:12 +0200 Subject: [PATCH 8/9] minor fixes --- README.md | 2 +- docs/contributing.md | 9 +++++---- docs/overview.md | 5 ++--- docs/starting.md | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 81842996..9febf434 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![javadoc](https://javadoc.io/badge2/com.helger/jcodemodel/javadoc.svg)](https://javadoc.io/doc/com.helger/jcodemodel) -This project provides modeling and exporting java source code at java runtime, either in a pre-processing phase or to acces them using a dynamic Classloader. +This project provides modeling and exporting java source code at java runtime, either in a pre-processing phase or to access them using a dynamic Classloader. It is a fork of the com.sun.codemodel 2.7-SNAPSHOT. diff --git a/docs/contributing.md b/docs/contributing.md index cab2a4df..c2845a43 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -16,7 +16,7 @@ Pull requests must follow my personal [Coding Styleguide](https://github.com/pha #### Tabs vs spaces -This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](../sh/tabspaces) makes that change, run it from the root project. +This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](../sh/cfg/tabspaces) makes that change, run it from the root project. What this script does : @@ -71,10 +71,11 @@ General convention is as such, for feature Feat : generat**ing** is `jcodemodel/ A generator generates a JCM that the plugin will export when requested. - - The generator module should be in the [../plugin/generators] submodule, with a module name starting with `GEN ` (in its pom) ; - - The testing module should be in the [../examples/plugins] submodule, with a module name starting with `XPL Generator ` . + - The generator module should be in the [plugin's generators](../plugin/generators/pom.xml) submodule, with a module name starting with `GEN ` (in its pom) ; + - The testing module should be in the [plugins examples](../examples/plugins/pom.xml) submodule, with a module name starting with `XPL Generator ` . -For example, the [HelloWorld generator](../plugin/generators/helloworld/pom.xml) and its [HelloWorld example](../examples/plugins/helloworld/pom.xml) modules. +For example, see the [HelloWorld generator](../plugin/generators/helloworld/pom.xml) and its [HelloWorld example](../examples/plugins/helloworld/pom.xml) modules. +The former is *named* `GEN Helloworld`, the later `XPL Generator Helloworld`. The testing module should not rely on internet data, as this can be an issue when remote host is down. With [correct configuration](../examples/plugins/helloworld/pom.xml) the plugin will apply the generator and produce the classes in `src/generated/java` , allowing the usual unit tests in that module. \ No newline at end of file diff --git a/docs/overview.md b/docs/overview.md index ae98118f..5d167423 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -6,11 +6,10 @@ The project is split in - The [root pom project](../pom.xml) - The [core project](../jcodemodel/pom.xml) lib to generate classes and resources programmatically. - - The [test project](../jccodemodeltests/pom.xml) validates the *generated* classes behavior. - - The [plugin](../plugin//plugin/pom.xml) to generate java classes in maven + - The [test project](../jcodemodeltests/pom.xml) validates the *generated* classes behavior. + - The [plugin](../plugin/plugin/pom.xml) to generate java classes in maven - The various [plugin generators](../plugin/generators/pom.xml) to load a JCodeModel in the plugin - The [examples](../examples/pom.xml) that showcase how to use JCodeModel, the plugin, the generators. - - The [beta](../beta/pom.xml) contains projects that may be merged into the core, or other modules, but could also be discarded entirely. ### Core classes diff --git a/docs/starting.md b/docs/starting.md index c68c3902..9cc94c34 100644 --- a/docs/starting.md +++ b/docs/starting.md @@ -2,7 +2,7 @@ The target audience is developers who intend to use JCM as a part of their production. -JCM at its core generates java source code, with the ability to do so at runtime and loaded the generated code, by a running java program. +JCM at its core generates java source code, with the ability to do so at runtime and load the generated code, by a running java program. It can be used to generate data structures used to parse files or resources, create database entities, load runtime information and validate against meta data. @@ -72,7 +72,7 @@ OR even (recommended) you remove the version line completely and instead import ### First program -Let's first make a simple program that generates a new, empty class. With [java 25](https://openjdk.org/jeps/445) you can create a file `JCMFirstProgram.java` containing only +Let's first make a simple program that generates a new, empty class. With [java 25](https://openjdk.org/jeps/512) you can create a file `JCMFirstProgram.java` containing only ```java void main() throws JCodeModelException, IOException { @@ -84,7 +84,7 @@ void main() throws JCodeModelException, IOException { } ``` -Then ask your IDE resolve the names for you. This should add imports at the top of the file +Then ask your IDE to resolve the names for you. This should add imports at the top of the file. If you are using java <25 then you need to use a full class. We made [one already](../jcodemodel/src/test/java/JCMFirstProgram.java) that contains those lines. @@ -103,7 +103,7 @@ Now that you have a main class that produces code, you may want to embed that co It's actually possible to have maven do two passes of compiling but this is a bad habit as it blurs the visibility of what is generated, embedded, and can lead to issues with non-deterministic approaches. See [stackoverflow](https://stackoverflow.com/questions/21342342/run-maven-compilation-twice) -#### Regorganising the maven project +#### Reorganising the maven project 1. You need to change your **root** module to a `pom` *packaging* (in your root `pom.xml`). This means, your root pom becomes an aggregation of other modules. This is the case, for example, for our [root module](../pom.xml) . Note that the root module can't anymore export java code by itself. Regardless, this is a good habit for maven projects, with your root module defining all the dependencies, properties, plugins, etc. . 2. You need one **generator** sub module in that root pom to have the class generation. This module will have the java class that we made previously. @@ -115,7 +115,7 @@ Your **core** pom.xml should now contain : ```xml - + my.project CodeGenerator From 30c689dd48dcb8a1cb9dcbeee9284ed4f5313fec Mon Sep 17 00:00:00 2001 From: glelouet Date: Mon, 8 Jun 2026 14:35:24 +0200 Subject: [PATCH 9/9] update tabspace script description --- docs/contributing.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index c2845a43..b01d060e 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -16,15 +16,14 @@ Pull requests must follow my personal [Coding Styleguide](https://github.com/pha #### Tabs vs spaces -This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them and when pulling them. A [specific script](../sh/cfg/tabspaces) makes that change, run it from the root project. +This project uses double-space for indentation. If you want to use tabs, you can ask git to modify the files when commiting them. A [specific script](../sh/cfg/tabspaces) makes that change, run it from the root project. What this script does : - - create the file .git/info/attributes with `*.java filter=tabspace` . This will tell git to apply the script tabspace on the *.java files - - run `git config filter.tabspace.clean 'expand --tabs=2 --initial'` to ask git to replace tabs with two spaces on commit of *.java files. - - run `git config filter.tabspace.smudge 'unexpand --tabs=2 --first-only'` to request git to replace double spaces with tabs when checking a *.java file out. - + - create the file .git/info/attributes with `*.java filter=tabspace` . This will tell git to apply the filter `tabspace` on the *.java files ; if the file already exists it is deleted. + - append the line `*.xml filter=tabspace` to this same file. This will tell git to apply the filter `tabspace` on the *.xml files. This is because `pom.xml` files are also supposed to be space-started. + - run `git config filter.tabspace.clean 'expand --tabs=2 --initial'` : Before committing (*clean*) files applied the *filter*`tabspace`, *git* must run the [expand](https://man7.org/linux/man-pages/man1/expand.1.html) command, replacing tabs with *2* spaces at the beginning of each line (*--initial*). This setting is repository-specific and can be removed by deleting the corresponding line in `.git/config` #### Eclipse