The structure of a java project has gone through some transitions in time. Here are some conventional examples.
Here is a simple java project created in eclipse for basic needs. Although this is lightweight and simple it offers no place to put resources.
eclipse-project/ |-- bin `-- src
Ant web project
Here is the legacy ant project layout before maven came along. It provides a place to put resources. However the problem is that if you put stuff in WEB-INF then it is not classpath accessible and, specific to eclipse, you cannot add WEB-INF as a source folder to add it to your editor classpath because it is nested in your output folder of WEB-INF/classes/.
ant-project/ |-- src |-- tests `-- webapp `-- WEB-INF `-- classes
Basic maven project
This is the standard maven layout and provides clean separation of every distinct responsibility of a project structure. It is very well defined and has no classpath problems and is my favourite.
basic-maven-project/ |-- pom.xml |-- src | |-- main | | |-- java | | |-- resources | | `-- webapp | | `-- WEB-INF | `-- test | |-- java | `-- resources `-- target |-- classes `-- test-classes
Advanced maven project
The advanced maven project structure is offered by M2Eclipse, the eclipse plugin, and has one advantage over the previous structure. It offers different output directories for eclipse and command line. This is useful when building in editor and command line and you don’t want them to conflict, clear or overwrite each other in the output directory. This helps also with setting editors and build tools to work independently if their settings differ.
advanced-maven-project/ |-- pom.xml |-- src | |-- main | | |-- java | | `-- resources | `-- test | |-- java | `-- resources |-- target | |-- classes | `-- test-classes `-- target-eclipse |-- classes `-- test-classes
So what must one consider when creating a new project structure? Sometimes the use of maven is not permitted either due to a legacy environment or due to a heavy investment in ant already. That is when it becomes necessary to think in terms of concepts and the pros and cons of different structures outside of the domain of specific build tools. The following are some recommendations to follow which make life a hell of a lot easier.
- Separate sources from tests. Yes I have seen them both together and it is a very bad idea.
- Separate resources from the output folder. This can take the shape of a resources/ folder by itself in its simplest form. The benefit of this is that it can be classpath accessible by your editor and your build tool and is not nested within your output folder and can therefore be added as a source folder within your editor. This also thereby provides a uniform classpath based access mechanism to all its contents independent of the tool used. The build tool can then be configured to copy its contents to the output folder.
- Optionally have separate output directories for different tools. At times for example it is necessary for eclipse and ant to operate on the same project but independently and in isolation especially when you are testing your build environment with various different tools and settings. Most of the time this is unnecessary and so optional.
- When accessing resources from your application always use classpath based paths relative to your classpath. Spring makes this dead easy by allowing various locator patterns that also interpret wildcards (classpath:, classpath*:, file:). If you are storing your resources in their own folder and that is added to the classpath then you can access its contents by using simply a slash. The build tool or editor will then copy your resources into the output folder where the classpath based access will continue to apply whether deployed or otherwise.
- When using components (jars) in your application containing resources such as spring context files and property files allow the application to aggregate. The component should only ever provide config and resources and never load them. It should also never access the application to load application specific content. The end-user application is where the control should lie and the components should remain subordinate and not only because the same component may be used in more than one disparate application.
- Use Spring to your benefit. Spring provides a uniform mechanism to load resources of different kinds. Use it instead of loading resources manually. Try to resist the temptation to innovate on the classpath and associated integration and build tools. Reinventing the wheel rarely pays off in a positive way in some common ground!
- Standardise on your editor if possible (non-essential) and if using source control check in your editor project configuration. It makes new check outs far more informative as to the project structure and classpath entries. If omitted or ignored it has be reconfigured from scratch every time.
This was a blog post on a rather simplistic and basic note. However I felt it was worth a mention at least once as there will always be legacy projects out there in need of inspiration. Classpath problems are fundamental and if they exist they tend to impact the application as a whole and its components and cause prolonged heartache. It’s worth having a clearly defined and justified strategy to begin with so that later on down the line your app can grow and change with ease.