📜 ⬆️ ⬇️

How to use maven to work with libraries that are not in maven

In this article I will tell you how to connect a library, which by default is not in maven, and how to connect another library, the sources of which are lost a long time ago.


I will also describe how to make a maven project that generates an artifact that is partly a library, and how to connect this library to another maven project.


This article is for those who are just starting to master java.


image


In my previous article it was said that maven itself downloads all the dependencies mentioned in pom.xml. But what will happen if he does not find any dependence? In this case, maven will say that the dependency is not detected and will interrupt the build process with an error. What to do in this case?


This question, in fact, falls into several questions, each of which must be addressed individually. The choice of the solution is determined by where this dependence is.


Dependence can be on the Internet in some place, the existence of which maven does not know. It can also be in the form of a jar file in your hands and, finally, in the form of source code, designed as a maven project.


We will talk about these three cases.


But first you need to briefly clarify one question.


Where maven downloads libraries


On the Internet there is a server on which java libraries are laid out. This server is called a repository, and in Russian - a repository. This is not some abstract, but a very specific resource, the address of which is sewn into the default settings of maven. Therefore, it is called the default repository. This is where maven will look for dependencies from pom.xml.


What if there is no library in the remote repository by default, but it is in another remote repository


The first and possibly the most frequent problem occurs if the library in this default repository is not available or if this repository is not available from the machine on which the assembly is being performed, for example, for security reasons.


The causes of the problem are slightly different, but the solution is the same - you need to specify the repository in which the dependencies are. This is either some other address on the Internet, or the address of the repository raised by admins on the local network.


How to tell the maven project where to look for an additional repository


In order to specify maven that dependencies should be sought not only in the default repository, there is a regular mechanism. This is how you can register another address for search.


<repositories> <repository> <id>id </id> <url> </url> </repository> </repositories> 

Next, we hooked up the Spring project repository, where you can find the latest versions of this library family. Here's what it looks like inside pom.xml


 <repository> <id>com.springsource.repository.bundles.release </id> <url>http://repository.springsource.com/maven/bundles/release </url> </repository> 

Now maven, when it does not find the dependencies in the repository by default, or finds that it is not available, it will not panic, but look for the library in another repository and, if everything goes according to plan, it will find it. It should be clarified here that if your program can be used as a dependency, for example, if it is a library itself, then putting the tag repository in pom.xml is not the best idea. The explanation of why this is so, is beyond the scope of the article, but you can read it here .


But it happens that there is no library in the repositories. For example, if these are drivers for MSSQL, or if they are a proprietary library that you recently purchased for a lot of money.


How to connect the library, which is not in the repositories


You can connect such a library in several ways. For example, if you have your own repository in the local network, then you can (and sometimes even need to) put the library there, and thus reduce the task to the previous one.


But, if possible, it is better to put such a library into a project and store it directly in the version control system. Then the library will be available to the program always and on any machine, and the step of copying this library to the repository can be omitted from the manual.


For handling such cases, maven also has a regular mechanism. We have just figured out how to specify maven remote repository, different from the default. So, it is not necessary to use remote storage. You can make a repository in the local file system, put the library there and instruct maven to look for dependencies there as well.


How to create your local repository


For this, as mentioned above, maven has a regular tool.


Suppose we have a library that is in a jar file called hello-world-library-1.0-SNAPSHOT.jar. We know about the library that it has one class HelloWorld, which includes one static method say, which prints in the console, as you might guess, Hello World.


We want to create a lib directory in the project directory, in which our additional repository will be located, and place the library there. For this it is enough to execute the following command in the project directory.


 mvn \ deploy:deploy-file \ -Durl=file:./lib \ -Dfile=hello-world-library-1.0-SNAPSHOT.jar \ -DgroupId=com.local \ -DartifactId=hello-world-library-local \ -Dpackaging=jar \ -Dversion=1.0-SNAPSHOT 

If you are using a Windows operating system, you need to replace \ by ^, that is, write


 mvn ^ deploy:deploy-file ^ -Durl=file:./lib ^ -Dfile=hello-world-library-1.0-SNAPSHOT.jar ^ -DgroupId=com.local ^ -DartifactId=hello-world-library-local ^ -Dpackaging=jar ^ -Dversion=1.0-SNAPSHOT 

Or you can simply remove the \ and write a command in one line.


 mvn deploy:deploy-file -Durl=file:./lib -Dfile=hello-world-library-1.0-SNAPSHOT.jar -DgroupId=com.local -DartifactId=hello-world-library-local -Dpackaging=jar -Dversion=1.0-SNAPSHOT 

Notice, as with any other artifact, for the library we need to come up with groupId, artifactId and version. We then specify them in pom.xml when we add the dependency.


Inside the directory that the team will create, there is a full repository, to use which, it is enough to indicate maven where it is located. All information about which libraries can be found there is contained directly in the directory structure of the newly created repository. For subsequent use of the repository, for example, on other machines, the deploy-file command is not necessary.


Letting the project know that the repository exists, and show where it is located, you can already described method, however, adjusted for the fact that the repository is local.


 <repositories> <repository> <id>localrep</id> <name>local repository</name> <url>file:${project.basedir}/lib</url> </repository> </repositories> 

Note the fifth line


 <url>file:${project.basedir}/lib</url> 

It says that you need to search for the repository in the project directory, to which the built-in variable maven project.basedir points.


The class using the library will be extremely simple, but for the order we give its code.


 package com; import static com.HelloWorld.say; public class Application { public static void main(String[] argv) { say(); } } 

It remains to add a dependency in pom.xml and you can build a project.


 <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>library-user-with-local-repository</artifactId> <version>1.0-SNAPSHOT</version> <repositories> <repository> <id>localrep</id> <name>local repository</name> <url>file:${project.basedir}/lib</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.local</groupId> <artifactId>hello-world-library-local</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project> 

Check:


 mvn clean compile exec:java -Dexec.mainClass="com.Application" 

Works!


The lib directory must be committed and the library will always be available to the project.


However, one rule should be kept.


It is necessary to update the version number of the library in the local repository each time the jar file changes.


Maven perceives the repositories as external, so if you do not change the version number, then maven will not use the library version from the lib directory, but the one that it has cached on the local machine. In this particular case, this should not play a role because of the SNAPSHOT suffix, but you need to know about it.


There is another common script. You have your own library, which you build yourself with maven and then connect to another maven project.


How to make your java library


In order to make a library, it is enough to write a class with the public modifier. And then you can use this class in the code to which the library is connected.


Here is such a class.


 package com; public class HelloWorld { public static void say() { System.out.println("Hello world"); } } 

Now you need to make a maven project that will build the library containing this class.


As we remember, from the point of view of maven, a library is just an artifact, so the glossary will look trivial.


 <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>hello-world-library</artifactId> <version>1.0-SNAPSHOT</version> </project> 

So, we have a class with a static method, we have a description of an artifact for maven. It remains only to collect this code to get a library, that is, a jar file.


Just write in the console:


 mvn package 

After that, a file with the name \ <artifactId> - \ <version> .jar will appear in the target directory, in our specific case - hello-world-library-1.0-SNAPSHOT.jar , which is your library.


How to connect the newly created library to your maven project


In order for the library to later be connected to another project, you need to write install instead of package .


 mvn install 

This will need to be done after each change in the library code, and on each computer on which we want to use this library.


Now you can make a new project that will use the library.


 <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>hello-world</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com</groupId> <artifactId>hello-world-library</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project> 

Inside the project there will be one class that uses a static method from the library to say Hello world. We have already seen this class.


 package com; import static com.HelloWorld.say; public class Application { public static void main(String[] argv) { say(); } } 

Check again:


 mvn compile exec:java -Dexec.mainClass="com.Application" 

Works no worse than the previous version!


What if your library uses another library?


The question would seem stupid, but just in case, we will conduct an experiment.


Let's create a library with non-empty dependencies.


 <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>hello-world-library</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> </dependencies> </project> 

and write code for it


 package com; import static org.apache.commons.lang3.ArrayUtils.*; public class HelloWorld { public static void say() { String[] phrase = {"Hello"}; phrase = add(phrase, " "); phrase = add(phrase, "world"); for (String word : phrase) { System.out.print(word); } System.out.println(); } } 

Now we will collect it


 mvn clean install 

Go to the directory with our project, which uses this library and try to build and run it.


 mvn clean compile exec:java -Dexec.mainClass="com.Application" 

And working!


How it works


Strictly speaking, knowing how the process is arranged inside is not necessary, but still very useful.


The mvn install command will compile the library, and then put it into the default local repository. That is, in the same place where all the libraries you have ever connected to maven projects are located, except, of course, those that are in the local repositories made by you personally.


Then, when building a project that uses this library, maven will look for it in the local storage, find and connect it.


Total



UPD : In the comments sshikov , igor_suhorukov , jbaruch and others have suggested that the libraries can not be stored together with the source, because for this there are other tools specifically designed for this, such as Nexus and Artifactory.


Here I completely agree. When it comes to large projects and corporate development, it cannot be any other way. But, from my point of view, there are cases when it is more convenient to do otherwise. I mean small projects created in the learning process, because it is the beginners who usually deal with such things, and there are cases when there is no access to the infrastructure, and you need to add the library to the assembly within 10 minutes. It was necessary from the very beginning to clarify that the speech in the article is about such cases.


Yes, storing libraries in a version control system is a hack. But, like all hacks, it is such a thing, which in some cases can be used and the possibility of the implementation of which would be nice to know.


The reasons why the technique proposed in the article is not suitable for corporate development are well disclosed in the comments. I also advise you to pay attention to the article from the Nexus developers, thanks to jbaruch for the link . The article is interesting, if I don’t find an existing translation in Habré, I plan to translate it and make it a separate post.


')

Source: https://habr.com/ru/post/323008/


All Articles