What is the Maven idiom for accessing configuration files? - java

For example suppose I'm using the standard project structure and have
src/main/config/config.xml
To access this I presume
new File("src/main/config/config.xml");
would be incorrect

There is no "Maven Idiom" for accessing configuration files. Maven is a build platform, not an execution platform. So the conventions for accessing configuration files that apply are really just the conventions of the Java platform that you are using; e.g.
the plain J2SE way of doing it, or
the J2EE and/or webapp way of doing it, or
the J2ME way of doing it, or
...
Maven only comes into the picture because you (presumably) have resource files in your project / version control that need to be included in the JAR or WAR or whatever artifacts that you are building. To get this to work in Maven, you simply need to understand how Maven copies non-Java files into the artifacts.
In the simple (JAR) case, the default behavior is to copy anything in src/main/resources/ into the JAR, with the same relative name; e.g. src/main/resource/foo/bar.xml becomes /foo/bar.xml in the JAR file.
For WAR files, the default is to copy anything src/main/webapp to into the WAR file. So if you wanted a file to be accessible in the webapp as a classpath resource with the name /foo/bar.xml you would put it in src/main/webapp/WEB-INF/classes/foo/bar.xml. (I'm assuming that you know how webapp classpaths work ... or that this isn't your use-case.)

A config file is just a resource on your classpath like any other, so use:
URL resource = getClass().getResource("config.xml");
You'll need to do the usual Use as Source Folder on your src/main/config folder for this to work in Eclipse with m2e.

I think config files should be in src/main/resources by default.

Related

Spring Boot classpath

In the Spring Boot's docs here, about serving static content, it says:
By default Spring Boot will serve static content from a directory
called /static (or /public or /resources or /META-INF/resources) in
the classpath.
I found that all the content in the directory:
src/main/resources
will be copied inside the classpath, so I can put my static content in:
src/main/resources/static
and all will work fine and I'm happy since I can have my static content under the src directory.
But, I have some questions about this:
Why the documentation doesn't say to put static content in src/main/resources/static instead of speaking about the classpath (I think this is a bit confusing)?
Is it good to assume that the content in src/main/resources/ will be always copied in the classpath?
Is there some Spring Boot official documentation explaining what I'm supposed to find in the classpath other than Java classes and packages (up to now I only know I can found all the content from src/main/resources/)?
/src/main/resources is a Maven project structure convention. It's a path inside your project where you place resources. During the build step, Maven will take files in there and place them in the appropriate place for you to use them in your runtime classpath, eg in an executable .jar, some physical file system location used in the classpath (with java's -cp option), etc.
I could choose to build my application myself or with a different build tool. In such a case, /src/main/resources would not exist. However, the intention is for the classpath to be the same, ie. to contain the same resources and .class files.
The Spring boot documentation talks about the classpath because it shouldn't make assumptions about how your project is set up.
The classpath also contains additional libraries (JARs), which also can have a static folder, which would then be included for serving static resources. So if the documentation would only state the folder src/main/resources/static, it would be incomplete.
Ad 2: As long as you don't mess with the default Maven configuration, then it's safe to assume this.
Ad 3: Maybe start with the official Oracle documentation: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html. Hint: Of course, it's not only the contents of the resources folder, which are in the classpath, but also of course all compiled classes, hence its name.
To add to previous answers, it's the Spring Boot Maven Plugin (spring-boot-maven-plugin in the pom.xml) that that enables you to run the application using Maven. One of its functions is to ensure contents in the app including dependency libraries are available on the runtime classpath, such as within the the executable JAR file.

How can I define a different target folder for some dependencies in Maven

I run many instances of the same web application under Tomcat and to save memory I copy some of the libraries to Tomcat's lib (tomcat\lib) and shared (tomcat\shared) folders. Libraries that go under lib can be found by both Tomcat and web applications, libraries that go under the shared-folder can only be used by web applications. My web application also need some libraries on the web application level so those libraries goes under WEB-INF\lib.
I have defined in my pom.xml that most libraries have a scope of provided so that they're not copied to WEB-INF\lib, however is there any way to define that I would like some libraries to go under a custom-defined folder; e.g. WEB-INF\lib\tomcat\shared and WEB-INF\lib\tomcat\lib, from where I could mover them manually to Tomcat's corresponding folders on the server?
That is not really the recommended way to package dependencies, as usually the web application would be deployed without furhter modification of the war file.
I think you can archieve what you want using the dependency:copy-dependencies goal, but it would require some configuration. You would have to set includeScope to provided, set the correct outputDirectory and then define the artifacts with the includeGroupIds or includeArtifactIds options.
Make a separate maven project which contains the war file and define the dependencies which should be located in the share-folder as scope: provided. Furthermore create an other separate module which has these dependencies and create an appropriate archive from it via maven-assembly-plugin...

How to access a XML file in a maven project so it stays available when packaged

I currently started working on a maven web-app project that needs to be launched with the jetty:run-exploded goal for development/debugging in eclipse.
Now, I have an XML file which contents I need to access at runtime. My problem is: where to put the file so that the code that does the reading works both in "exploded" and packaged (i.e. in the WAR) mode?
Putting the file in src/main/java (so as to be in the classpath) won't cut it since maven filters out all non-java files on packaging.
When the file is in src/main/resources, one mean would be to figure out the root path of the project (during eclipse development) and look into that directory - but this won't be the case anymore when the project will be packaged.
Of course I could go into writing code that tries to read the file from both locations, but this seems rather cumbersome. Any suggestions?
Files in src/main/resources are copied to the target/classes directory and are available on the class path. Just read them from the class path. As explained in How do I add resources to my JAR? from the maven documentation (with a test resource here):
In a unit test you could use a simple
snippet of code like the following to
access the resource required for
testing:
...
// Retrieve resource
InputStream is = getClass().getResourceAsStream("/test.properties" );
// Do something with the resource
...
In such case I put the file under src/main/resources directory and use Spring's ClassPathResource. This way the file is accessible in IDE, during Maven build process and in runtime.

What is the best practice for the location of Java application configuration files?

Is there a best practice for where configuration files should be stored in a Java project. The file type is a Java properties file in this case, but I do use other file types in other projects.
Would the recommendation vary from stand alone application(.jar) to web app(.war)?
You'll find that many open-source projects follow the directory structure used by Maven. In this setup your application source code is kept in src/main/java, application resources, including properties files, in src/main/resources, and other config files in src/main/config. Files related to unit tests use a similar directory structure; src/test/java and src/test/resources.
Personally I tend to use this layout because of its widespread use. I also keep an "etc" directory beneath the project root to house files that aren't directly related to the application. For example, I keep configuration files for PMD and Checkstyle in etc.
In general a common practice is to have a resources directory for configuration files which is copied into the build artifact by the build process. Maven uses this in its default project structure. Within the resources directory, you might also have a META-INF directory and/or a WEB-INF directory in an application packaged as a war.
I use:
META-INF/ for jar files
WEB-INF/ for war files

What are some additional directory conventions for Maven projects?

Maven 2 uses a standard directory layout for projects, documented here:
http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
What I'm wondering is: are there recommended conventions for other projects besides the plain-vanilla Java library, Java EE and WebApp projects? Specifically, where to place ant files, start scripts, configuration files, sample applications, etc.
In addition, what is the convention for placing files outside of the src/ directory tree? For example, is it common to place documentation under doc/ (as sibling of src)?
Is there a page where these conventions are compiled? If not, can other readers provide examples from their own projects?
The main folder I place extra config files in is under src/main/java/resources. Usually I created sub directories under there. The tests can have their own config files src/test/resources.
You can use directives in the build section of the pom.xml to specify additional resources directories and where to copy files to specific places in the target directory. Usually a convention arises for the language or framework you are trying to use. In which case the mess can be hidden in a parent pom.xml
See http://maven.apache.org/pom.html#Resources
I don't think there is an official layout for desktop applications, but this is the layout we use for ours.
src/main/config - Config files, copied and filtered to ${project.build.directory}/config.
src/main/scripts - sh, bat, README and other plain-text files that are copied and filtered to ${project.build.directory}.
src/main/bin - Binary files that are not filtered and copied to ${project.build.directory}.
src/main/build - Any additional scripts, ant files, or resources used by the build process but not included in the application.
src/main/assembly - Assembly descriptor to create application assembly.
Copy dependencies to ${project.build.directory}/lib using maven-dependency plugin.
Bonus points if you use a shared assembly descriptor jar which includes the config and lib directories along with standard file types to share with all your projects. A good set of default file types to include is .sh, .bat, and .exe with executable permissions; .jar, .zip, .txt, .pdf, .xml, .properties, .conf, .ico, .png, .jpg with standard permissions.
Add the config directory and lib/ prefix to the classpath using the maven-jar plugin to make a runnable jar.
Add a installer profile that builds an assembly of your application using the maven-assembly plugin and your assembly descriptor. This assembly can then be consumed by a separate installer project if needed.
Avoid putting anything else at the src/ level. Instead put documentation inside the src/site/ directory (eg. src/site/sphinx) or src/doc if you really need to.
Put all the above configuration in a parent/corporate pom to share with all your projects. Simply reference the maven-dependency, maven-resources, maven-jar, and maven-assembly plugins in you project to build an entire application with almost no configuration (don't forget to set the main-class for the maven-jar plugin).

Categories

Resources