Maven compile does not create class files - java

I have a 3 module maven project with parent pom. From parent when I run a maven clean-compile-test. It fails at test phase and gives tons of compilation errors saying "symbol not found" for my local classes.
I discovered using IntelliJ ide if I use the "Make Project" button before I run a maven test, then maven test works!
Edit: Now I figured out that probelem is maven compile does not create class files in target folder for some reason this is my maven compiler plugin configuration in parent pom file:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<excludes>
<exclude>**/*.*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
Any ideas?

One more thing.
Look in pom.xml, tag <packaging>. If it sets in pom, Maven shouldn`t create class-files for you. Change it for appropriate package - jar, war ...

Maven doesn't care about missing symbols in the package phase; missing symbols will only be reported during the compile phase (= when the Java compiler is run by Maven).
To find out why it can't find the symbols, you need to examine one of the errors. Look into the folder target and check if the missing class exists in there (at the right place).
mvn clean deletes this folder but mvn compile should put new files in there.
If you can't see anything obvious, then save a list of all the files in the target folder somewhere. Then build the project in IDEA. Again create a list of all files.
Sort both lists and then compare them. That might give you an idea what is wrong. My guess is that you configured Maven in an odd way (moving source folders or target folders).
EDIT The configuration
<excludes>
<exclude>**/*.*</exclude>
</excludes>
tells Maven "ignore all source files" which is equivalent to "don't do anything". Remove this and try again.

Related

Syntax for excluding deprecated directories with Maven

I have a few directories in my Java project that hold deprecated code: com.company.deprecated and com.partner.company.deprecated. I want to exclude everything in these two "deprecated" directories from Maven compilation, regardless of content or directory structure inside them, so I have created a build tag like this at the very end of my POM:
<!-- Exclude directories that hold deprecated code -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/com/company/deprecated</exclude>
<exclude>**/com/partner/company/deprecated</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
This POM handles a module inside a larger project, but the deprecated code isn't used anywhere else inside other modules, so I don't think there are any conflict issues going on with other POMs. I have tried putting the "build" element at the end of either the specific module POM or the project POM, and get the same compilation errors each time.
As far as I can tell, this should exclude the deprecated directories from my Maven build, but I keep getting compilation errors in files within the "deprecated" directories. I have tried the double asterisk syntax above, absolute paths, and wildcards after "deprecated" but nothing seems to work. I've gone through StackOverflow and haven't found anything exactly like what I'm trying to do, although I am still relatively new to Maven so it is very possible there is something I'm just being dense about.
Can anyone please help me with the proper syntax (or perhaps a different plugin?) for this issue? Thank you!

What do I need to add to my pom.xml to run this specific Java file?

I'm not a Java dev and am unfamiliar with the packaging and building of Java programs. I'm trying to run this file: https://github.com/CodinGame/SpringChallenge2020/blob/master/src/test/java/Spring2020Main.java
by doing
mvn clean install
java -jar .\target\spring-2020-1.0-SNAPSHOT.jar
but I get this error:
no main manifest attribute, in .\target\spring-2020-1.0-SNAPSHOT.jar
I can't figure out for the life of me what I need to add to the pom.xml or whatever else I need to do to get this to work.
Any help will be appreciated.
A few things to understand about Java:
1) If you have a Maven project like this, code is divided between src/main/ and src/test/ directories. src/test/ is intended for unit tests. In your case, Spring2020Main is not actually set up as a unit test, so I'm not sure what the author intended here.
2) When you compile using mvn clean install, a jar (library) is built, but nothing from src/test will be included in the output.
Generally, tests are executed during build. And this one would have been, except it's not set up as a real junit test, so it didn't run during build.
3) You can move the file from src/test/java to src/main/java and it will be built into your resulting jar.
4) In this case, when you run the JVM, you need to specify a classpath. This is a list of all libraries to include when the application starts. You also need to specify the (fully qualified) name of the class to run:
java -cp target/spring-2020-1.0-SNAPSHOT.jar Spring2020Main
...the above won't work directly since there are more unsatisfied dependencies (the top level pom.xml brings in at least 3 other deps you'd also need to provide on the classpath).
As others pointed out, a solution could be to build a self-executing jar, but simplest for you would be to run this from an IDE:
Run this from IntelliJ. If you haven't installed it, install it.
1) File > New From Existing Sources, find the directory where this is coned to.
2) When asked, Import Project from Existing Model (Maven)
3) When the Project view is available (alt-1), or View > Tool Windows > Project, you can expand the structure till you find Spring2020Main in the test directory.
4) Right-click it and select Run.
For me, it exposed a web server running at http://localhost:8888/test.html
You can follow the steps below:
Move Spring2020Main.java to src/main/java/com/codingame directory
Add the following to your pom.xml after the </dependencies>:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.codingame.Spring2020Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Run maven build using mvn clean install
Execute the program using java -jar target/spring-2020-1.0-SNAPSHOT.jar
Info: Apache Maven Shade Plugin helps in building what is called an uber-jar or a fat-jar. This means that all the dependencies are packaged as part of the resultant jar file without the need for any 'libraries' that you'd need to add in the classpath when executing the jar file. As part of the final jar, we need to specify which file needs to be treated as the main file to be executed. This is typically done using META-INF/MANIFEST.MF file inside the uber-jar. That's what the transformer specified inside the configuration of the plugin does for us.
The project you've linked has only a basic setup for compilation (that would be enough to run it from IDE though).
What you need is an executable jar. Check this thread.
As others mentioned (and I failed to notice) the class you linked to is a test class, so it may not be included in a jar by default. Run it through IDE or set it up in a proper source directory.

Adding folders in maven project

let us say I have a standard maven project with the standard four Directories
src/main/java
src/main/resources
src/test/java
src/test/resources
Now let us suppose, I create a subdirectory named "clojure" under "src/main".
Are then the source files under "src/main/clojure" automatically compiled when a build is run or do I somehow have to tell to maven, via configuration of some plugin (e.g. build-helper-maven-plugin), that it also has to compile the sources under "src/main/clojure"?
In others words, does the creation of any folder that is not ".../java" or ".../resources" require an explicit configuration in the pom.xml so that the sources there are taken into account by maven??
Any help would be appreciated.
Regards,
Horace
A Maven project is usually built with a single compiler, which looks for all its source files in those folders known as source folders to Maven. Depending on the project, such source folders may be added automatically, e.g. src/main/java. If a different compiler is used, additional folders may automatically be added, e.g. src/main/groovy.
Sometimes Maven integrations in IDEs (like Eclipse or IntelliJ) do not pick up folders for non-Java projects, even though the correct Maven plugins are in the POM, say e.g. for building a Groovy project.
So even though a build on the command line may run nicely with files in src/main/groovy, the folder may not be detected as a source folder when importing the project in an IDE. In such cases you may have to add the additional source folders, e.g.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/groovy</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Yes, maven needs to "know" what those directories mean, though a clojure build plugin may use that directory by convention - see for example: https://github.com/talios/clojure-maven-plugin
Apache maven has a Standard Directory Layout which it understands out of the box.
To make maven understand any other structure than the above, you'll have to override these settings in pom.xml.
Look at this section of POM reference.

dependency not found at runtime maven

I'm new to maven and somewhat new to java. Tried google and related sources, but I didn't find one which resembled my situation.
Right now, I have maven project X and Y. X can be seen as a shared library with some utilities, Y is a simple JFrame with a "hello world" printed and a call to a static method in X.
I do a "run as maven install" on project X, I get a "build successful". I add project X as dependency in project Y (using the pom-editor in Eclipse, browsing the repository and locating it). I do a "run as maven package" on project Y, I get a "build successful". Upon running project Y either via java -jar or inspect the produced jar, project X is missing everywhere and I get a fancy class not found exception. Eclipse finds it and there are no compile errors in the source editor.
Why is it only working in the Eclipse editor and not as jar?
POM:
<dependency>
<groupId>com.company.deployment.shared</groupId>
<artifactId>com.company.deployment.shared</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
Maven doesn't produce a combined JAR file for you. What Eclipse is doing is looking at the Maven configuration and adding all the required classes / jars to your classpath for you when it runs.
If you want to run your program from the command-line, you will need to add all the JARs manually to your classpath.
Alternatively, you could run your program directly from Maven which should set up all your dependencies. There are a number of options depending on what you want to do, i.e. if it's an application which is meant to be run by an end-user you could look into the one-jar Maven plugin.
I recommend that you take a look at the Maven shade plugin. This produces an "uber-jar" comprising your project and all of its dependencies. It can also do other things such as setting the entry point class to make your JAR file an executable JAR.
You may also find exec-maven-plugin helpful
mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"] ...
mvn exec:exec -Dexec.executable="maven" [-Dexec.workingdir="/tmp"] -Dexec.args="-X myproject:dist"
If your client can not download dependencies from maven m2 repo on the fly like behind firewall or no internet connection, then you also need to package the dependencies using maven-dependency-plugin to copy all dependencies and maven-assembly-plugin to assemble dependencies
It doesn't work because Maven resolves dependencies when building your project, but doesn't put all the dependencies magically in your jar. You're supposed to run your app with all its dependencies in the classpath:
java -classpath X.jar;Y.jar com.foo.bar.Main
Or you have to customize the maven jar plugin in order to create an executable jar, as described here. And you may also use the maven assemby plugin to copy all your Y project's dependencies to the target directory, next to the generated Y.jar.
The artifact produced in project Y contains only build results in project Y only, not including its dependencies.
If you want to build a JAR in Y, which u can execute directly, you can consider using assembly plugin.
For example, the easiest way to build a uber-jar for project Y:
<project>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-all-in-one-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
...
</project>
Apart from a normal artifact, an assembly which contains classes etc from dependencies will be created, which is suitable to be executed by java -jar
visit http://maven.apache.org/plugins/maven-assembly-plugin/ for more sophisticated usage.
Phil Sacre already explained the basic problem well (there basically is just no information on where to find the X.jar embedded in your Y.jar).
Additionally you can also look at the appassembler-maven-plugin (which can e.g. generate launch scripts for your Y project that already have the right classpath set) and/or the exec-maven-plugin (which you can use to e.g. directly launch Y with the right classpath using maven).

Where in maven project's path should I put configuration files that are not considered resources

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.

Categories

Resources