9

I am trying to use external library inside my maven project. Since I want the project to build out of the box on any machine, I don't want to use mvn install solution. I have therefore defined local repository in my pom.xml:

    <dependency>
        <groupId>com.test</groupId>
        <artifactId>fooLib</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    ....
    <repository>
        <id>in-project</id>
        <snapshots>
            <updatePolicy>always</updatePolicy>
            <enabled>true</enabled>
        </snapshots>
        <name>In Project Repo</name>
        <url>file://${project.basedir}/libRepo</url>
    </repository>

The problem is when I replace the jar in libRepo (without updating version number since it is just another snapshot) that this updated jar is not used (old version from .m2 directory is used instead) even for mvn -U clean install How to make maven to update this jar?

EDIT: According to What exactly is a Maven Snapshot and why do we need it? maven shall try to find newer version of SNAPSHOT dependency, "even if a version of this library is found on the local repository". What is wrong with my setting?

DIRTY SOLUTION: Based on answer from Maven 2 assembly with dependencies: jar under scope "system" not included following extension of my original solution seems to work:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-install-plugin</artifactId>
            <executions>
                <execution>
                    <id>hack-binary</id>
                    <phase>validate</phase>
                    <configuration>
                        <file>${repo.path.to.jar}</file>
                        <repositoryLayout>default</repositoryLayout>
                        <groupId>com.test</groupId>
                        <artifactId>fooLib</artifactId>
                        <version>1.0-SNAPSHOT</version>
                        <packaging>jar</packaging>
                        <generatePom>true</generatePom>
                    </configuration>
                    <goals>
                        <goal>install-file</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

As mentioned in comment to that solution, it does not work alone, thus it works in combination with in-project repository (which works when the dependency is not available in local .m2 repository) and this second parts refreshes .m2 during every build.

However it is still not clear to me why ordinary "SNAPSHOT" mechanism does not work (i.e. current dirty solution would work also without SNAPSHOTs as local .m2 repo is explicitly updated every time). Is there any cleaner way?

SOLUTION (based on Aaron's answer & discussion): The problem was that I tried to install file into libRepo using install-file. The actual solution is that if library updates, use

mvn deploy:deploy-file -Dfile=fooLib.jar  -DgroupId=com.test \
    -DartifactId=fooLib -Dversion=1.0-SNAPSHOT -Dpackaging=jar \
    -Durl=file://..\libRepo -DrepositoryId=in-project

to deployed it to repo. After proper deploy, maven correctly handles SNAPSHOTs.

larsw
  • 3,790
  • 2
  • 25
  • 37
sodik
  • 4,675
  • 2
  • 29
  • 47
  • Are you using `mvn -U clean install` while building the dependency or while building the main project? – renke Feb 25 '14 at 13:38
  • I am using maven only for "main" project. The `fooLib` is not maven project and is build independently. I just want to use newer snapshot of fooLib in my maven ("main") project. – sodik Feb 25 '14 at 13:51
  • So you'll have to install `fooLib`manually, because it will never be updated in your .m2 folder, unless its version changes. – renke Feb 25 '14 at 13:53

3 Answers3

6

If you use a repository for this, then Maven will copy the JAR once into it's local repository (usually in $HOME/.m2/repository/). Unless the version number changes, Maven won't consider this file to have changed and it won't copy it. Note that the version number is the only thing that Maven looks at; it doesn't care about checksums or file sizes or dates.

Incidentally, snapshots are assigned a version number internally for just this purpose: So that Maven can internally notice that a snapshot has been updated.

I suggest to use a system dependency instead. That way, the actual JAR is going to be added to the classpath (without any copying or stuff). You also don't need to replicate a repo structure for this approach and it will clearly communicate your intent.

[EDIT] I understand that Maven handles dependencies with scope system differently. I'm not sure whether this makes sense or not (if it uses the dependency to compile, it surely can use it to run?)

As I see it, you have these options:

  1. Install the dependency into your libRepo using deploy:deploy-file instead of copying it yourself. That should update the meta data in such a way that Maven will copy it again when you run mvn install again on the real project.

    Note that file:install doesn't work. The file plugin is used to access the local repository but you need to use the deploy plugin which knows how to update a shared / server repository.

  2. Install the dependency into your local repo; I suggest to use a script for this that you can include in your project. That way, you avoid all the problems and it will be easy to set this up on a new machine.

  3. Change the version number of the dependency but that's tedious and you might get into trouble when the real version number of the dependency changes.

  4. Set up a local repo server for your company and deploy the dependency to it. That will take a few hours but a) you will get a local cache of all your dependencies, making your initial builds faster and b) it will make setup for additional developers much faster.

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • at first it looks like it has helped, I can see the dependency within `mvn dependency:tree` but it is not added to classpath when executing it e.g. via `mvn exec:java` nor it is added to manifest with `maven-jar-plugin` (however `maven-dependency-plugin:copy-dependencies` works) – sodik Feb 25 '14 at 14:45
  • Ask a new question and show us how the code you used to add the dependency. – Aaron Digulla Feb 25 '14 at 15:26
  • there is already such question (not mine): http://stackoverflow.com/questions/2065928/maven-2-assembly-with-dependencies-jar-under-scope-system-not-included However it is not dealing with snapshots... beside this detail solution is identical to my original one. – sodik Feb 25 '14 at 17:04
  • my "plugin" is e.g. ' org.apache.maven.plugins maven-jar-plugin true false lib/ ${jar.mainclass} ${project.version} ' – sodik Feb 25 '14 at 17:04
  • I'm confused. The question doesn't seem to be related (it deals with building assemblies and not with `exec:java`. Also why do you post the config for the JAR plugin when you want to know how to add a dependency? – Aaron Digulla Feb 26 '14 at 08:53
  • all is connected with dependencies. `exec:java` shall put all dependencies on classpath, but is not happening for system dependencies, so I am getting NoClassDefFound. And if you check JAR plugin, it shall add classpath to manifest, and in this case there is a same problem with system dependencies. – sodik Feb 26 '14 at 09:01
  • I begin to understand where this is going. See my edits. – Aaron Digulla Feb 26 '14 at 09:04
  • You write "local .m2 repo is explicitly updated every time". Do you have any proof for that? Do you see Maven download the JAR from `libRepo` every time you run it? – Aaron Digulla Feb 26 '14 at 09:06
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/48494/discussion-between-sodik-and-aaron-digulla) – sodik Feb 26 '14 at 15:31
1

Maven will never read the jar present inside any library folder. You must first understand how maven works. The only place where maven looks for jar is the localRepository (.m2), if absent it searches the other repository, mentioned in your POM.xml

ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
  • Isn't that I can add a dependency with scope as system and add a file path and asking the POM to read it ? – Vinay Veluri Feb 25 '14 at 13:35
  • But since the jar is already present in your local repository, it will always find it before hitting any other repository ! – ItachiUchiha Feb 25 '14 at 13:37
  • so there is no way how to get fresh snapshot of any dependency? – sodik Feb 25 '14 at 13:54
  • yes there is, you have to add the jar as the dependency to your project and build the jar before building your project. You can go through *parent/module* part for more details – ItachiUchiha Feb 25 '14 at 13:56
  • 1
    While your answer is technically correct, it doesn't really apply here since the OP has put the JAR inside of a repository which happens to be inside of his project structure. Maven **can** read it from there but the key issue here is that it does that only **once**. – Aaron Digulla Feb 25 '14 at 14:05
  • Will maven not read the jar first from the localRepository(.m2), before looking for it into the project structure ? – ItachiUchiha Feb 25 '14 at 14:09
  • it looks like it is reading. Question is how to force him not to look in .m2 but check the repository instead. `fooLib` is not maven project and I don't want to build it every time with "main" project. – sodik Feb 25 '14 at 14:49
1

The previous answerer (and one commenter) pointed out, that maven looks within the local project-repository only once, and on subsequent builds it gets the cached jar from the .m2-repository.

I just found a workaround for the need to increment the version number (e.g. on small changes of a dev-library):

First reinstall the jar into your local project-repository:

mvn install:install-file -DlocalRepositoryPath=repo -DcreateChecksum=true -Dpackaging=jar -DgroupId=com.johndoe.dev -DartifactId=Helpers -Dversion=0.1 -Dfile=C:/path/to/helpers.jar

(Where -Dfile could point to an external Project which produces the helpers.jar)

Then purge just this specific artifact in the .m2-repository:

mvn dependency:purge-local-repository -DmanualInclude=com.johndoe.dev:Helpers:0.1

(With com.johndoe.dev as the GroupId, Helpers as the ArtifactId and the same version installed in the previous step)

Executing the latter step, maven rebuilds the artifact inside .m2 using your local project-repository jar-file.

Alternative and maybe dirty variant: Just copy helpers.jar to C:\Users\johndoe\.m2\repository\com\johndoe\dev\Helpers\0.1\Helpers-0.1.jar (don't know about linux as I haven't used mave there).

Community
  • 1
  • 1
JackLeEmmerdeur
  • 724
  • 11
  • 17