Classes in test package not available at compile time in IntelliJ - java

I have a setup like the following:
Where I have two modules: modulea and moduleb, in this case, moduleb has a dependency to modulea defined as:
<dependency>
<groupId>org.example</groupId>
<artifactId>module-a</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
</dependency>
This allows me to use ClassInTestA in ClassInSourceB without any issues while developing:
However, when I try to build the project, this error prevents IntelliJ to complete the build:
I have come across similar questions in SO:
Question 1
Question 2
Question 3
However, none of the proposed solutions has been able to help my case. I have created an MVCE that is available here as zip and in GitHub.
The real-world project I'm working is neo4j, which follows this structure. Moreover, compilations using mvn install/package work without any issue, the problem appears when working inside IntelliJ.

In general, it makes sense to "open" a new project by building it first outside of IntelliJ with mvn clean package and then import it by just "open"ing the parent module. This worked for me:
And even after a rebuild:
If you don't want to reimport your project by deleting all IDEA folders and files and use the described way above, you can try to build the project via the Maven toolbar (clean and package on the parent module) and then use the "Reimport all Maven projects" button:
At least sometimes this works for me, but honestly not always.

Test classes aren't packed in the final artifact. To share the test classes you'll have to use the jar maven-jar-plugin in modulea:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
and add a dependency in moduleb's pom.xml:
<dependency>
<groupId>org.example</groupId>
<artifactId>module-a</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>tests</classifier>
</dependency>

Test sources are not included during the compile phase
See Apache Maven Compiler Plugin:
compiler:compile is bound to the compile phase and is used to compile
the main source files.
I think main sources should not depend on test sources. Test sources are only for testing the main sources. You could place ClassInTestA under module-a/src/main/java.

Related

maven: execute without actually building anything

I have a project with finalised version in pom files , lets say 12.3.45 .
I have built the code for this version some time ago already, all the built jars are in the local maven repo.
Then at some point I have run mvn clean, so all the target folders are being removed.
And now I want to execute some code, as quickly as possible, using mvn exec:java. Preferably without building anything, because why not? all the jars at some point were already built, and I know there were no code changes after that. How can I force maven to execute the code as fast as possible , not recompile anything, and just reuse the jars from the local repo?
Thanks.
If your artifacts are in a local or remote repository you can use them as dependencies.
You can use exec-maven-plugin's options includeProjectDependencies or includePluginDependencies to use them in java execution
https://www.mojohaus.org/exec-maven-plugin/java-mojo.html#includePluginDependencies. includeProjectDependencies option is enabled (true) by default.
You can execute exec-maven-plugin without building anything with mvn exec:java command
Instructions:
To run exec-maven-plugin you would need a main class to run. I assume you have one in your project. If you don't - you need to make a separate project with a main class.
Create a blank maven project.
In the project add exec-maven-plugin configuration. Set the mainClass
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>pack.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Include you artifacts as dependencies to the project
<dependencies>
<dependency>
<groupId>my.group</groupId>
<artifactId>myartifact</artifactId>
<version>12.3.45</version>
</dependency>
</dependencies>
Run mvn exec:java to execute com.my.package.MyMainClass main class from my.group.myartifact artifact
Edits:
includeProjectDependencies option is enabled (true) by default

Why is my maven dependency in included .jar not found in final .war

I have a .jar we have developed in-house. It is built using maven. It has a dependency, commons-codec, that is provided from the maven central repository.
.jar .pom dependency ("myjar"):
<packaging>jar</packaging>
...
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
...
.war .pom dependency:
<packaging>war</packaging>
...
<dependency>
<groupId>com.myco.mydiv</groupId>
<artifactId>myjar</artifactId>
<version>1.5.54</version>
</dependency>
....
I can build and test this jar without issue. When the jar is included as a dependency in a .war, it builds without problem, but at run time, the external dependency for commons-codec produces a class def not found exception.
I tried changing the scope for commons-codec in the .jar .pom to 'compile' but this did not help.
I can fix this by adding the commons-codec dependency to the .war .pom, but this is not the right way to fix it (I think) as it requires all projects using the .jar to know about this dependency and include it likewise. I could also include the external .jar in the WEB-INF/lib to solve this, but it also seems like the incorrect approach.
What is the best way to handle this? Why is the common-codec dependency not visible at run time for the .war?
This conversation seems to touch on a similar issue: https://github.com/ReactiveX/RxNetty/issues/292
And so I wonder if there is a right way to handle this with nested dependencies.
But I just noticed this answer, which seems to show the right way to do this:
https://stackoverflow.com/a/98743/2266428
jar-with-dependencies via the maven-assembly-plugin seems to solve the problem but at the expense of a very large .jar (6 MB in my case).
After trying multiple approaches, it turns out the Shade plugin was exactly what was needed. The below added plugin configuration to my .war .pom, exactly as shown, added the dependency to the jar and made it available to the .war at runtime.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
Unzipping the initial .jar shows that the following path and classes are now included in the build:
org > apache > commmons > codec > *.class

Maven failsafe does not run tests in submodule

I have a project with a parent directory containing the following in its pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.20.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
and
<modules>
<module>submodule</module>
</modules>
The submodule subdirectory again contains a pom.xml with a reference to its parent artifact. The subdirectory also contains a number of integration tests which run fine if I move the failsafe plugin into the submodule's pom.xml and then invoke mvn verify from the parent directory but this will not work with this current (preferred) setup (There are no errors, the tests are simply not executed).
I've tried adding the submodule artifact to dependenciesToScan in the failsafe plugin's configuration but that did not solve the problem. Do I need to add the submodule as a dependency in the parent pom.xml? Because that results in a "dependency is referencing itself" error while processing the pom.xml.
Help would be appreciated.
EDIT: I have figured it out, someone else working on the project had wrapped the build section in a profile section, I did not realise this at first because the whole file is rather large and unwieldly and I had overlooked the corresponding git commit. By undoing that change and following the instructions in the link posted by Gerald Broser I managed to solve my problem (I suppose just executing the respective profile would have also done it, but that change was uncalled for anyway).
See Maven Failsafe Plugin / Usage / Usage in multi-module projects:
When you are defining a shared definition of the Failsafe Plugin in a parent pom, it is considered best practice to define an execution id in order to allow child projects to override the configuration.
try to call
mvn clean verify -P <module>

Issues with Maven In Eclipse

Am newbie in Maven and trying to build my first app with Maven using the latest version of Eclipse. After right-clicking the pom.xml file choosing Run-As and Maven Build, i get a window with the title "Edit Configuration and Launch". This window has 3 text areas "Goals","Profiles","User settings".
My question is what should i enter into these text areas to run my application successfully?
Thank you
EDIT
My application is a simple console application in Eclipse so i just want the output from the Main class to appear on the console.
Depending on your project, goals can be one of the life cycle phases phases to achieve.
To start with you can use "install" or "compile". The other two can be left empty for now.
We can attach maven-antrun-plugin:run goal to test phase. This will allow us to echo text messages for different profiles. We will be using pom.xml to define different profiles and will activate profile at command console using maven command.
Assume, we've created following pom.xml in C:\MVN\project folder.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.companyname.projectgroup</groupId>
<artifactId>project</artifactId>
<version>1.0</version>
<profiles>
<profile>
<id>test</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>Using env.test.properties</echo>
<copy file="src/main/resources/env.test.properties" tofile
="${project.build.outputDirectory}/env.properties"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
And assume, we've created following properties file in C:\MVN\project\src\resources folder.
env.properties
environment=debug env.test.properties
environment=test env.prod.properties
environment=prod
Now open command console, go to the folder containing pom.xml and execute the following mvn command. Pass the profile name as argument using -P option.
C:\MVN\project>mvn test -Ptest
For better clarification: http://www.tutorialspoint.com/maven/maven_build_profiles.htm
To expand on the previous answer, I would most often use 2 goals: clean install or clean compile
The clean remove all files generated by the previous build.
The install will run phases 1-7 below which copies the resulting jar into your local maven repository (usually a .m2 directory in your home directory) so that it is available and can be referenced as a dependency to other maven projects.
The compile will only run phase 1-2 below which compiles your code, but stops before running any configured tests.
Other options are copied from the Maven site below for convenience.
A Build Lifecycle is Made Up of Phases
Each of these build lifecycles is defined by a different list of build
phases, wherein a build phase represents a stage in the lifecycle.
For example, the default lifecycle comprises of the following phases
(for a complete list of the lifecycle phases, refer to the Lifecycle
Reference):
validate - validate the project is correct and all necessary
information is available
compile - compile the source code of the
project
test - test the compiled source code using a suitable unit
testing framework. These tests should not require the code be
packaged or deployed
package - take the compiled code and package it
in its distributable format, such as a JAR.
integration-test - process and deploy the package if necessary into an environment where integration tests can be run
verify - run any checks to verify
the package is valid and meets quality criteria
install - install
the package into the local repository, for use as a dependency in
other projects locally
deploy - done in an integration or release
environment, copies the final package to the remote repository for
sharing with other developers and projects.

Maven: best way of linking custom external JAR to my project?

It's my first couple of days learning Maven and I'm still struggling with the basics. I have an external .jar file (not available in the public repos) that I need to reference in my project and I'm trying to figure out what my best option is.
It's a small scale project without a central repository for libraries, so it has to be either a local repository (somehow added to source control, don't know if it's supposed to work that way?) or the .jar needs to be stored on disk outside of any formal repository.
1) What's my best option for adding the .jar file to my project's references with maven given that I want both the project and the library to be in source control?
2) I still can't seem to have Eclipse see the dependency. I manually added it to the section of the pom, and it shows up fine in the Dependencies list in m2eclipse. mvn compile and mvn package both succeed, but running the program results in:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
LibraryStuff cannot be resolved to a type
This is after editing the POM as:
<dependency>
<groupId>stuff</groupId>
<artifactId>library</artifactId>
<version>1.0</version>
<systemPath>${lib.location}/MyLibrary.jar</systemPath>
<scope>system</scope>
</dependency>
Should I be executing mvn install:install-file even thought I already have the pom.xml edited as above?
Thanks!
You can create an In Project Repository, so you don't have to run mvn install:install-file every time you work on a new computer
<repository>
<id>in-project</id>
<name>In Project Repo</name>
<url>file://${project.basedir}/libs</url>
</repository>
<dependency>
<groupId>dropbox</groupId>
<artifactId>dropbox-sdk</artifactId>
<version>1.3.1</version>
</dependency>
/groupId/artifactId/version/artifactId-verion.jar
detail read this blog post
https://web.archive.org/web/20121026021311/charlie.cu.cc/2012/06/how-add-external-libraries-maven
I think you should use mvn install:install-file to populate your local repository with the library jars then you should change the scope from system to compile.
If you are starting with maven I suggest to use maven directly not IDE plugins as it adds an extra layer of complexity.
As for the error, do you put the required jars on your classpath? If you are using types from the library, you need to have access to it in the runtime as well. This has nothing to do with maven itself.
I don't understand why you want to put the library to source control - it is for sources code not binary jars.
This can be easily achieved by using the <scope> element nested inside <dependency> element.
For example:
<dependencies>
<dependency>
<groupId>ldapjdk</groupId>
<artifactId>ldapjdk</artifactId>
<scope>system</scope>
<version>1.0</version>
<systemPath>${basedir}\src\lib\ldapjdk.jar</systemPath>
</dependency>
</dependencies>
Reference: http://www.tutorialspoint.com/maven/maven_external_dependencies.htm
The Maven manual says to do this:
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
update We have since just installed our own Nexus server, much easier and cleaner.
At our company we had some jars that we some jars that were common but were not hosted in any maven repositories, nor did we want to have them in local storage.
We created a very simple mvn (public) repo on Github (but you can host it on any server or locally):
note that this is only ideal for managing a few rarely chaning jar files
Create repo on GitHub:
https://github.com/<user_name>/mvn-repo/
Add Repository in pom.xml
(Make note that the full path raw file will be a bit different than the repo name)
<repository>
<id>project-common</id>
<name>Project Common</name>
<url>https://github.com/<user_name>/mvn-repo/raw/master/</url>
</repository>
Add dependency to host (Github or private server)
a. All you need to know is that files are stored in the pattern mentioned by #glitch
/groupId/artifactId/version/artifactId-version.jar
b. On your host create the folders to match this pattern.
i.e if you have a jar file named service-sdk-0.0.1.jar, create the folder service-sdk/service-sdk/0.0.1/ and place the jar file service-sdk-0.0.1.jar into it.
c. Test it by trying to download the jar from a browser (in our case: https://github.com/<user_name>/mvn-repo/raw/master/service-sdk/service-sdk/0.0.1/service-sdk-0.0.1.jar
Add dependency to your pom.xml file:
<dependency>
<groupId>service-sdk</groupId>
<artifactId>service-sdk</artifactId>
<version>0.0.1</version>
</dependency>
Enjoy
Don't use systemPath. Contrary to what people have said here, you can put an external jar in a folder under your checked-out project directory and haven Maven find it like other dependencies. Here are two crucial steps:
Use "mvn install:install-file" with -DlocalRepositoryPath.
Configure a repository to point to that path in your POM.
It is fairly straightforward and you can find a step-by-step example here:
http://randomizedsort.blogspot.com/2011/10/configuring-maven-to-use-local-library.html
If you meet the same problem and you are using spring-boot v1.4+, you can do it in this way.
There is an includeSystemScope that you can use to add system-scope dependencies to the jar.
e.g.
I'm using oracle driver into my project.
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.3.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/extra-jars/ojdbc14-10.2.0.3.0.jar</systemPath>
</dependency>
then make includeSystemScope=true to include the jar into path /BOOT-INF/lib/**
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
and exclude from resource to avoid duplicated include, the jar is fat enought~
<build>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.jar</exclude>
</excludes>
</resource>
</resources>
</build>
Good luck!
Maven way to add non maven jars to maven project
Maven Project and non maven jars
Add the maven install plugins in your build section
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>${version.maven-install-plugin}</version>
<executions>
<execution>
<id>install-external-non-maven1-jar</id>
<phase>clean</phase>
<configuration>
<repositoryLayout>default</repositoryLayout>
<groupId>jar1.group</groupId>
<artifactId>non-maven1</artifactId>
<version>${version.non-maven1}</version>
<file>${project.basedir}/libs/non-maven1.jar</file>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
<execution>
<id>install-external-non-maven2-jar</id>
<phase>clean</phase>
<configuration>
<repositoryLayout>default</repositoryLayout>
<groupId>jar2.group</groupId>
<artifactId>non-maven2</artifactId>
<version>${version.non-maven2}</version>
<file>${project.basedir}/libs/non-maven2.jar</file>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
<execution>
<id>install-external-non-maven3-jar</id>
<phase>clean</phase>
<configuration>
<repositoryLayout>default</repositoryLayout>
<groupId>jar3.group</groupId>
<artifactId>non-maven3</artifactId>
<version>${version.non-maven3}</version>
<file>${project.basedir}/libs/non-maven3.jar</file>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
</executions>
</plugin>
Add the dependency
<dependencies>
<dependency>
<groupId>jar1.group</groupId>
<artifactId>non-maven1</artifactId>
<version>${version.non-maven1}</version>
</dependency>
<dependency>
<groupId>jar2.group</groupId>
<artifactId>non-maven2</artifactId>
<version>${version.non-maven2}</version>
</dependency>
<dependency>
<groupId>jar3.group</groupId>
<artifactId>non-maven3</artifactId>
<version>${version.non-maven3}</version>
</dependency>
</dependencies>
References Note I am the owner of the blog
Change your systemPath.
<dependency>
<groupId>stuff</groupId>
<artifactId>library</artifactId>
<version>1.0</version>
<systemPath>${project.basedir}/MyLibrary.jar</systemPath>
<scope>system</scope>
</dependency>
The pom.xml is going to look at your local repository to try and find the dependency that matches your artifact.
Also you shouldn't really be using the system scope or systemPath attributes, these are normally reserved for things that are in the JDK and not the JRE
See this question for how to install maven artifacts.
Note that all of the example that use
<repository>...</respository>
require outer
<repositories>...</repositories>
enclosing tags. It's not clear from some of the examples.
The best solution here is to install a repository: Nexus or Artifactory. If gives you a place to put things like this, and further it speeds things up by caching your stuff from the outside.
If the thing you are dealing with is open source, you might also consider putting in into central.
See the guide.
With Eclipse Oxygen you can do the below things:
Place your libraries in WEB-INF/lib
Project -> Configure Build Path -> Add Library -> Web App Library
Maven will take them when installing the project.
If the external jar is created by a Maven project only then you can copy the entire project on your system and run a
mvn install
in the project directory. This will add the jar into .m2 directory which is local maven repository.
Now you can add the
<dependency>
<groupId>copy-from-the=maven-pom-of-existing-project</groupId>
<artifactId>copy-from-the=maven-pom-of-existing-project</artifactId>
<version>copy-from-the=maven-pom-of-existing-project</version>
</dependency>
This will ensure that you
mvn exec:java
works. If you use suggested here
<scope>system</scope>
Then you will have to add classes individually while using executing through command line.
You can add the external jars by the following command described here
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> \
-DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>
The most efficient and cleanest way I have found to deal with this problem is by using Github Packages
Create a simple empty public/private repository on GitHub as per your requirement whether you want your external jar to be publicly hosted or not.
Run below maven command to deploy you external jar in above created github repository
mvn deploy:deploy-file \
-DgroupId= your-group-id \
-DartifactId= your-artifact-id \
-Dversion= 1.0.0 -Dpackaging= jar -Dfile= path-to-file \
-DrepositoryId= id-to-map-on-server-section-of-settings.xml \
-Durl=https://maven.pkg.github.com/github-username/github-reponame-created-in-above-step
Above command will deploy you external jar in GitHub repository mentioned in -Durl=.
You can refer this link on How to deploy dependencies as GitHub Packages GitHub
Package Deployment Tutorial
After that you can add the dependency using groupId,artifactId and version mentioned in above step in maven pom.xml and run mvn install
Maven will fetch the dependency of external jar from GitHub Packages registry and provide in your maven project.
For this to work you will also need to configure you maven's settings.xml to fetch from GitHub Package registry.

Categories

Resources