Runtime dependency included in war - java

I am a little surprised: I declared a dependency in maven pom as runtime and it was still included in war.
I honestly expected it not to do this...
I used junit just for the purpose of demonstration...:)
For example:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Thanks,
Roxana

Some maven-scopes:
if the dependency is needed in production and has to be delivered along with the application use scope runtime
if the dependency is needed only for (unit-)testing and should not be delivered use scope test
if the dependency is needed in production but is already part of the container (e.g. tomcat, JBOSS) use scope provided

If you want something at runtime then it has to be in the package. Otherwise where will the software know where to find it.
What were you expecting? And most importantly, why are you including JUnit in Runtime? It should be in test scope.

Related

Can't complete mvn verify without jersey-container-servle-core

I am trying to run mvn verify on my project with 2.22.1 Jersey version.
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.22.1</version>
<scope>runtime</scope>
</dependency>
When running mvn verify it says I am using jersey-container-servle-core and I haven't declared it. According to Jersey notification this dependency in already in jersey-container-servlet. Any idea?
The problem was that I used the "core" dependency in unit test and in web.xml.
In order to solve it I can do either:
Change continar-servlet to compile and then I will have it for test as well. Because container-servlet include "core", it will work on test as well.
Add jersey-container-servle-core just for test scope or with runtime

Is it possible to include only the used classes in a war file with maven build?

Say I have this dependency in my pom.xml file:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
</dependency>
When I do a
clean install
all the javaee-api-6.0.jar will be included in the war file under WEB-INF\lib folder.
Is it possible that instead of including the whole jar, only classes that I use and their dependencies are included?
If you're deploying into a Java EE application server, that entire JAR is already provided by the application server, and can be omitted from the WAR file. You can accomplish this by putting it into the provided scope:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
That makes that dependency available for compilation and test execution, but will not package it into the WAR.
In contrast, trying to determine which individual classes you need so you can only include their class files is an ultimately pointless endeveor. The JVM only loads classes when they are used - that is, unused classes are not loaded.
It is generally impossible to identify the used classes at compile time due to reflection. For instance, consider:
System.console().printf("Please specify the implementation class to use");
String className = System.console().readLine();
FooService service = (FooService) Class.forName(className).newInstance();
service.work();
You can get the JVM to log which classes are loaded, but different executions can use different classes ...
It's not a viable option - at least not in maven, although You know which classes You are using, but You don't know what are the dependencies for each class that You imported - so it might be impossible satisfy it's requirements. This is why we are using tools like maven - to ease the process importing a library.
Read some more about reduce size of built project and see what are Your options there
Except for UberJAR, Your biggest chance (IMHO) would be to identify libraries that are provided by the container, and use provided scope for them.
You also could integrate 3rd party tools like ProGuard
You could use exclusions.
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<exclusion>
<groupId>...</groupId>
<artifactId>...</artifactId>
</exclusion>
</dependency>
But I don't think you could exclude at class-levels. This only excludes dependencies useful when there are conflicting dependencies in your project.
It is really not a viable option in my opinion ,as its almost impossible to know internals what all classes are required at runtime until and unless you are seeing the,implementation of all the,3rd part apis that you are using.
I also think the whole idea behind the maven is to ease the development and build process so that you won't have to do any effort in identifying the artifacts that are required at runtime or compile time. Maven will automatically figure out that for you.

How to configure Maven to use GWT module sources for compiling but do not include them in final JAR/WAR?

I have a GWT project and I want to use some other in house GWT libraries as dependencies.
We do not want to include sources in our final build. Most open source GWT libraries include sources in the JAR, but we want to keep sources separate, use them to compile, then throw them away.
Is there a way to do this with Maven?
Set the scope to provided
<dependency>
<groupId>com.you.gwt</groupId>
<artifactId>gwt-ui</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
Brad's answer will fix the problem in a very narrow scenario. Setting the scope to provided totally avoids the jar from being pushed into War's lib. This is not what you would need in use case of the "lib" on to server side code. This usually happens
1) Constants.
2) DTO's/Beans.
3) RPC service interfaces
4) Request Factory proxy declarations
You have to have a mix of approaches.
1) Brad's approach when the "lib" in purely client and has no chance of being used in server clode.
2) Modularize code to have Constants/DTO's/Proxy/RF related interfaces and any such code in a project that generates two artifact jars.
A) One with classes only - to be used to push stuff in to web-inf/lib i.e scope compile/runtime.
B) Another with sources/classess - to be used with gwt compilation i.e scope provided.
Generating two jars might seem redundant. This is the only sane option i have tried. Keen on check whether there is any other option that will be suggested.
There are two kind of library (package in jar file) in GWT:
Server side library like "gwt-servlet.jar" does not contain source code in jar file and you can add maven dependency like this in your pom:
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwtVersion}</version>
<scope>runtime</scope>
</dependency>
Client side library like "gwt-user.jar" which contain source code in jar file, this kind of library does not require to package in your war file and you can add maven dependency like this in your pom:
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwtVersion}</version>
<scope>provided</scope>
</dependency>
Have a nice time.

Maven 2 - different dependency versions in test and compile

I have project that depends on commons-httpclient [2.0] (compile).
I would like to write some jbehave tests - jbehave-core 3.4.5 (test).
Both this dependencies depend on commons-lang but in different versions - 1.0.1 and 2.5.
When I execute mvn package I get [BUID FAILURE] in tests section.
There is an exception for my testcase in surefire-plugin output:
java.lang.NoSuchMethodError: org.apache.commons.lang.StringUtils.substringBeforeLast(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
As I looked in source code - in commons-lang 1.0.1 - indeed, there is no StringUtils.substringBeforeLast(...) method.
Why maven uses commons-lang from commons-httpclient (compile) and not from jbehave-core in testing?
I can't afford to exclude this conflicting dependency in commons-httpclient so it must stay in compile time.
So how can this be resolved - commons-lang 2.5 version in testing and 1.0.1 in compile time?
Maven 3:
Maven 3 will attempt to obtain the nearest dependency, effectively ensuring that only one of the compile or test scoped dependency is used for both the compile and test phases.
(Thanks Vineet Reynolds)
Maven 2 (OLD):
try to define 2 different <dependency> tags with different versions and scopes. Use tag <scope>test</scope> inside dependency for tests and <scope>compile</scope> for compilation.
In Maven 3, you can trick maven by adding a dot after groupId
<dependency>
<groupId>groupId.</groupId>
<artifactId>artifactId</artifactId>
<version>version1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version2</version>
<scope>compile</scope>
</dependency>
The sequence matters here. need to have test first and then compile.
<dependency>
<groupId>groupId.</groupId>
<artifactId>artifactId</artifactId>
<version>version1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version2</version>
<scope>compile</scope>
</dependency>
Adding a dot doesnt work in pom.xml as . is converted to slash which in return generated incorrect URL.
Is thr any other way to do this
It's a really bad idea to have two different versions for compile and test dependency:
Your non-test code might rely on behavior of the newer JAR and fail when using classes of the older JAR.
When you use the older JAR in your tests, the non-test code would fail with the old JAR.
Otherwise you could have used the older JAR anywhere, with the same version...
If you get both JAR versions into your classpath, you cannot know which one gets picked up when running your tests. That's also a bad idea.
Hence you should get non-test and test to the same JAR version dependency.

Where I can find #Inject jar

I'm following the MVC unit test instructions from this site,
but I cannot find the jar for the #Inject annotation. Does anybody know where the jar is?
Via Maven:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Or from the Project Home Page: http://code.google.com/p/atinject/
Also, this MvnRepository.com page provides the necessary configurations for other build tools like Ivy, Gradle etc.
Using javaee-api instead of javax.inject I ran into a bunch of issues.
After some digging I found out that you need to add it with scope provided or otherwise it will add a Listener (com.sun.faces.config.ConfigureListener) at runtime.
Another issue is that apparently the implementation to inject is different. Fields annotated with #inject remained null. By replacing the official sun jar with the javax.inject, this no longer happened.
Note that i'm not an expert, I might be running into side-effects, but figuring this out took me such a long time, that I felt I had to share my findings so far.
You can use Sun's official:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
</dependency>
Cheers!

Categories

Resources