This question already has answers here:
Migrating complex project from Ant to Maven - How to handle unusual folder structures?
(2 answers)
Closed 9 years ago.
The problem is quite simple: there is an ant project that I should port to maven. As maven has a recommended/expected project directory structure, this would implicate much manual work if I restructure the directories of the java files. On the other hand, the project would also not be very happy with this solution, not mentioning others, using the packages of the current project.
Do you have any idea, how it would be possible to migrate to maven without having to change the directory structure? Thank you also in advance.
It is strongly recommended that you use Maven's standard directory structure, but you can set a custom src directory in your pom. Something like:
<build>
<sourceDirectory>path\to\actual\src</sourceDirectory>
</build>
The following might be what you're looking for: Handling unconventional source directory for a web project in maven
Edit: The following is a list of default settings that are set in the Maven Super POM and can be overriden in your project's pom.xml
<build>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<finalName>${artifactId}-${version}</finalName>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>
I would strongly recommend you commit to the restructure. You are only adding to your problems if you do not.
However, if you really must maintain your original structure you could make use of soft folders of some sort. On Windows you can use SymLinks - I expect there are other alternatives for other OS's.
Make a new folder beside your sources folder (I called mine Maven). In that folder, build a structure that mirrors the required Maven structure but only place pom files in it. Make symlinks to the old location.
It is possible to automate this but it takes some work.
I would only recommend this solution while you are in a transition phase while some developers are still building with ant or you are transitioning your code to the new structure in your SCC system.
Related
I believe this problem has been asked before on stackoverflow. And I'd like to mention that I tried the solutions that came with the questions related to mine. The one that came the closest to my problem was:
Load properties file in JAR?. Sadly the solution described there didn't work for me. And due the age of the question I thought asking it again is the way to go.
Heading on to describing my problem.
So currently I'm working on a library project which has been setup with maven and creates an extension for the current Spring AMQP project.
The goal here is to supply a JAR file which can be included into another project to support a specific way of communicating over a message broker.
At this point I'm implementing the configuration option to allow users to configure the messaging client to their liking. But while i was testing the functionality of this feature I hit a problem while using the library in an executable JAR.
While running it in the Eclipse workspace everything seems to work just fine. But when I try to run it from my desktop (as a runnable JAR) the properties file does not seem to be found anywhere.
Just to give a quick overview of the workspace/projects setup as described above:
The project structure of both project reflects the Maven default one:
- src/main/java
- java source files
- src/main/resources
- resource files
- src/test/java
- java test files
- src/test/resources
- test resource files
Where the library file contains a default.properties file in the src/main/resources folder and the chatclient project a custom.properties file.
Once the runnable JAR file has been build it has the following structure in it.
- com
- junit
- META-INF
- org
- resources
- default.resources
- custom.resources
I believe the resource files should not be located there. but in the META-INF/maven folder instead. After trying out stuff like:
Adding a META-INF folder into my src/main/resources folder and putting the property files there.
Adding a MANIFEST file with Class-Path: . in it.
Loading the file in multiple ways in code.
But nothing seems to work. I guess it is Maven related and a simple change in the pom.xml could fix it. Sadly my knowledge on the Maven project setup and pom related subjects is very basic (this is my first project using maven). And I can't seem to find any documentation on it, even though I know it should be there (probably a problem caused by me).
Before I forget to mention it. I load the property files using this way:
Properties props = new Properties();
prop.load(<custom static class>.class.getResourceAsStream(filename));
return props;
Also the pom.xml for my library looks like:
-- Artifact stuff --
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
-- Dependency stuff --
And the one for the project that uses the library look like:
-- Artifact stuff --
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.maxxton</groupId>
<artifactId>async-amqp-messaging</artifactId>
<version>0.2</version>
</dependency>
</dependencies>
-- Other stuff --
I hope there is someone who's a little more advanced on this subject and could help find a solution for this problem. And if you need any additional information on the project files/structure, please let me know. I'd gladly share it with you.
Update (28-04-2015 {1})
For testing I created a sample project which tries to load property files the same way as the scenario described above.
Even while following the Maven documentation (Using the META-INF folder) I was not able to load the properties.
For the sake of this question I uploaded the testing workspace here.
I hope someone could help me fix this, as the normal way as described on the Maven website does not seem to work for me.
Update (28-04-2015 {2})
Well I managed to fix a part of the problem.
Since I added the configuration for the maven-assembly-plugin (building runnable JAR with deps), I was able to get the correct structure within my JAR file.
The thing I added was:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>project</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>com.test.project.Application</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Then when running clean compile assembly:single I managed to get the right structure.
JAR root
- com
- META-INF
- MANIFEST.MF
- default.properties
- custom.properties
While this fixes a part of the problem. The file loading still results in a NullPointerException.
Final Update (04-05-2015)
After a long Maven struggle I managed to get everything the way I want it to be.
Following the advice given by both #Deepak and #Joop Eggen, I did some research on how to have all the dependencies in a lib folder as jar instead of unpacking them in a 'uber' jar. After trying loads of stuff I stumbled upon this answer. Following the instruction there seems to create this structure:
- runnable.jar
- lib
- spring-amqp.jar
- spring-core.jar
...
When following #Joop Eggen's advice I managed to get the property loaded the way I want to. So it seems this question has been answered. Currently I'm still figuring out how to award each answer as I'm not able to split the bounty into two pieces. I'll get back on that.
Side Note
Although I awarded both the bounty and the answer to #Joop Eggen does not mean that #Deepak's answer did not contribute. It did give some great information on best practice, but was not as complete as the accepted answer. So please when finding your answer here give him some of the credit too.
There are two ways to get resources,
with a ClassLoader against the entire class path using absolute paths (without /...),
with a class, using a relative (...) or absolute (/...) path inside the jar of that class.
The latter seems more direct, and can be used as:
getClass().getResource("/...");
ClassInJar.class.getResource("/...");
Now getClass() is only possible in a non-static object and is dangerous too: the actual class might be some child, not in the library jar.
On the actual structure of your application. I know a maven directory convention:
src/main/java/...
src/main/resources/...
where /... gets into the jar/war; the package directory.
Reassembling jars is not good. There always is the Class-Path: ... entry in META-INF/MANIFEST.MF. Following the basic maven conventions is best.
The solution to this is simpler, however there are couple of concepts that I would like you to be aware off.
It is not a good practice to create one big jar by using maven assembly plugin. In your examples, you are using small jars both developed by you, so it might seem okay. But as your real projects get bigger, this is not ideal, you would want separation of different modules and not one big jar. The ideal practice is opposite to what you are trying to achieve - you should aim to have smaller and smaller jars. You might in future want the convenience of replacing these smaller jars without having to deliver the entire package again.
You would surely not want to unpack 3PP jars and package them as your own jar!
Based on the above, you might wonder how do you create executable jars. Well, the answer is having the dependent jars in the class-path. When executing the "project" jar, you should have the "library" jar in the class-path and it will be able to find the properties file inside as expected.
You places the properties files in META-INF directory. The right place for them is the resources folder. And if you follow the point No.1, things will work as expected.
I have a war packaging Maven project, in which I have a Java properties files called myapp.properties. In this properties file, I store some parameters, for example, database connection parameters, which will be used by the webapp.
Either in a continuous integration environment or in my development environment, I want to set some testing parameters in myapp.properties to connect to my test database for example.
At the same time, I want to leave these parameters blank in my final war package so that users can add these values by themselves during deployment to their environment. The final war package should be a build artifact generated in the continuous integration environment.
Essentially, there are two versions of myapp.properties file I want to use in different cases. My question is, what is the Maven way to solve this problem? I use Eclipse + WTP + m2eclipse in my development environment, and I hope the solution can works well together with my development tools.
You can have a look at this blog: http://blog.jayway.com/2010/01/21/one-artifact-with-multiple-configurations-in-maven/
They build different war-files and use different classifier (instead of different profiles).
I am not sure if it is the maven way, but it works for some of my projects.
i would try it with
pom.xml for your project (or parent pom)
<build>
...
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
...
</build>
in your properties file(s) e.g.
db.url=${db.url}
and in your settings.xml (see http://maven.apache.org/settings.html#Profiles)
<db.url>jdbc:mysql://localhost:3306/testdb</db.url>
depending on your development stage (local, build server, etc.) you can use different db.url values
this will not leave the db.url property blank, but each time you package the artifact you dont want it really to stay blank do you ?
I would like to have multiple GWT projects that share common code. Is this possible? AFAICT my GWT projects need to each have their own directory, with source directly underneath, which seems to preclude code-sharing. I tried using linked folders, but GWT didn't seem to like that (described here).
If I want to do this, is my only choice to turn the code I want to share into a .jar file, and then inherit that in each of my projects' XML files? Is there a way to make eclipse automatically do this packaging, or would I need some sort of 'change-shared-code/compile-jar/use-in-other-project' loop?
Are there any other solutions?
I solve this problem with help of maven. The common code is packaged as separate maven project and then used as library. Here are snippets from pom.xml file:
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.0.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>2.0.4</version>
<scope>provided</scope>
</dependency>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/client/**/*.java</include>
<include>**/client/**/*.properties</include>
<include>**/shared/**/*.java</include>
<include>**/shared/**/*.properties</include>
<include>**/*.gwt.xml</include>
</includes>
</resource>
</resource>
</build>
The above build configuration copies additional source files needed by GWT compiler into final jar.
In case of using eclipse as IDE, the m2eclipse plugin can be used for handling all the dependencies automatically. It is possible to have all the projects opened in single workspace and classpath of the common project will be shared. The only drawback is the requirement of invoking project > clean from time to time (will force embedded maven to copy all the resources specified in the snippet above).
I think all you need to do is make two separate GWT projects, e.g. project A for shared code and project B that uses code from project A.
Once you have these two projects, two steps are required:
Add project A to project B's build path in Eclipse.
Inherit project A's gwt.xml in project B.
You should now be able to use hosted mode / compile within Eclipse.
I tried to convert a project to a maven one... it has its .java files in other location than /src/main/java , when i run maven install, all the files (.hbm , .xml) except those .class occurs in my jar.
This is build part from pom.xml :
<build>
<resources>
<resource>
<directory>${basedir}/src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<fork>true</fork>
<compilerVersion>1.5</compilerVersion>
<compilerArguments>
<encoding>UTF-8</encoding>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
Using the above code, .class files are missing from my jar... and no error messages are displayed on console, is it necessary to move them to /src/main/java package structure ?
Also, what could be the reason for this behavior , some missing dependencies ?
I did a change moving them to , src/main/java and i got some exceptions on console , but i am still confused if i "must" add them to this "src/main/java" structure...
Please give me an idea about this...
Thanks
You can configure the source directory to be the same as the resources like this:
<build>
<sourceDirectory>${basedir}/src</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
</build>
It not strictly necessary - its configurable - but Maven comes with a standardized project layout and it is highly recommended to embrace it, like others Maven conventions (don't fight against Maven, adopt it).
I understood that you are migrating from Ant to Maven but you are IMO not on the right path, bending Maven to make it fit in your existing project structure/workflow is just not the recommended approach:
Maven strongly suggests using its conventions (over configuration) to ease things. Not doing so makes things more complicated and generate useless configuration overhead.
When deviating from the defaults, you're kinda on your own.
Not using defaults might result in bad surprises, some (poorly) implemented plugins might be using hard-coded paths (like src/main/java, target/classes, etc) and won't like changing defaults.
etc, etc, etc.
The recommended way would be to transform your existing structure into a maven compatible modular structure and to adopt the standard Maven layout.
Adopting Maven standards and conventions will just make your Maven life easier in the long run and you get a standardized structure, which Maven is much about.
I think enough people wrote similar advices so I won't insist more. But you should listen to these advices (and not insist trying to make Maven fit in your existing structure), especially since you're new to Maven. From my point of view, you're not migrating from Ant to Maven, you're trying to migrate Maven to an Ant build.
See also
How to convert from Ant to Maven in 5 minutes
Convert Ant Projects into Maven Safely in Five Phases
Have a look at the Super POM. That is the place you get the 'convention' from. You might have to change some settings in your project POM if you have a differnet project layout but it is no good advice as mentioned here before.
By far the easiest solution (if possible in your circumstances) is to move the code to /src/main/java, since that is where maven expects it. It that is not possible, you at least need to tell maven where to find the sources. From your POM I don't see anywhere where you did that.
If you want to use Maven, the path of least resistance is adhering to the Maven conventions. Surely you can have a different source path, but it is definitely more complicated (it seems that the only way is to pass the source directory as a compiler argument), and what do you gain? I believe moving your source directory is much easier.
I have a simple java maven project. One of my classes when executing needs to load an xml configuration file from the classpath. I don't want to package such xml file when producing the jar but I want to include a default xml file in a zip assembly under a conf subfolder and I also want this default xml to be available in the unit tests to test against it.
As I see it there are 2 possible places of this default xml:
src/main/resources/conf/default.xml
src/main/conf/default.xml
Both solutions demand special pom actions:
In solution 1, I get the auto copy to target folder during build which means it is available in testing but I also get it in the produced jar which i don't want.
In solution 2, I get the jar as I want it(free of the xml) but I manually have to copy the xml to the target folder to be available for testing. (I don't want to add src's subfolders in test classpath. I think it is bad practice).
Question: what is the best solution of the two?
- If the correct is 2, what is the best way to copy it to target folder?
- Is there any other solution better and more common than those two?
(I also read Where should I put application configuration files for a Maven project? but I would like to know the most "correct solution" from the "convention over configuration" point of view and this link provides some configuration type solutions but not any convention oriented. Maybe there isn't one but I ask anyway. Also the solutions provided include AntRun plugin and appAssembler plugin and I wonder if I could do it with out them.)
The question is what is the best solution of the two? If the correct is 2, what is the best way to copy it to target folder? Is there any other solution better and more common than those two?
Since you want that file to be copied to the target/classes folder, it has somehow to be considered as a resource (so either put in under src/main/resources or declare src/main/conf as resource directory). And if you don't want it in the final jar, configure the Maven JAR Plugin to exclude it:
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<excludes>
<exclude>**/conf/*</exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
For the assembly part, assembly descriptors are pretty flexible so it should be possible to achieve what you want regardless of the choice. I'd suggest using the easiest setup though.
My solution was to use two profiles: Development (default) and Packaging
My default / section contains both src/main/resources and src/main/conf. I call this my Development profile, which is an implicit profile.
My packaging profile is an explicit profile which is defined under section. There under / I only mentioned src/main/resources. When I'm running my packaging script (we currently have this external to maven since its building an RPM out of our WAR), I'm running 'mvn install -Drpm' to activate my Packaging profile (rpm is the id for the Packaging profile.
If this wasn't clear enough, feel free to ask more questions.
You could place it in src/test/conf/default.xml. Your testclasses can find it, but it wont be packaged using the standard method.
With an additional assembly you can package it from there. That step is always necessary.
A different solution could be to create a separate maven module and place it in /src/main/resources/conf/... .Then make this jar a test dependency. You do not need to do any special plugin configuration, but I think it is overkill for a single file.
If your packaging is war, you can use the packagingExcudes configuration option of the maven-war-plugin:
<project>
...
<build>
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<!-- Exclude abc.properties found in src/main/resources/ (ends up getting packaged in WEB-INF/classes/) -->
<packagingExcludes>
WEB-INF/classes/abc.properties
</packagingExcludes>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Use commas to separate between multiple resources you want to exclude. Also, you can use wildcards and regex in your excluded paths. For regex, it's in the %regex[YOUR_REGEX_HERE] syntax. Check the documentation for more details.