Is there any way to override "provided" maven scope from command line? - java

I am quite new to maven and inherited an old application which I need to maintain. It has couple of provided libraries (which are provided by the container). I am wondering whether there is any way to generate a war with all the dependencies (including the provided libs) without modifying the pom.xmls. (there are quite lot) Is there any way to override the scope for all libs from the command line?
My challenge is that I am dealing with an enterprise application with quite deep dependency graph and there are lot of provided dependencies all over the places. As a part of my experimentation I would like to generate a war which is self contained and have all the dependencies. Updating the dozens of poms and changing the scope is not what I am looking for. Is there any way to do this from the command line?

You only have to change the one pom that creates the war. In this pom, specify the dependencies that are currently "provided" with the desired scope.
Maven computes the transitive dependencies for the war project based on the modules that it depends on and is bringing in those particular dependencies with a provided scope. You can think of this as defining the default configuration for those dependencies. You can override the default (inherited) scope by explicitly specifying the dependency in your war module with the desired scope.
In my opinion, the non-war modules probably should not be setting the scope to provided and instead should leave this decision to the module that will actually create the runnable artifact (e.g., your war module). For example, if you were to make a fat jar to execute the code as a standalone app (vs. a war in a container that provides those dependencies), you probably would want to include them in the jar.

Related

Filtering out provided dependencies for a war

If I build a war for a specific platform (e.g. Wildfly), I need to filter out dependencies that are already provided by the platform.
Up to now, we do this by using a special BOM that lists all the provided dependencies with scope provided. Alternatively, one could also use the Maven war plugin to exclude the dependencies when building the war.
What is the preferred way?
Provided scope is there for this specific reason.
From maven documentation
provided
This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
The transitive dependencies of the provided scope will be also be in provided scope unless it is explicitly added in compile scope. If exclution is used it may cause jar conflict unless those jar are also excluded.
Also provided scope works with other packaging like ear

Is this duplicating a Maven dependency in a multi module project (i.e Spring)?

Here is the simple situation breakdown and I'd like to know if I'm doing this optimally or if there is a better convention. I have created a dummy project just for learning purposes.
I have created a multi module Maven project. Simply the parent POM, with two sibling child POMS, one being a service layer, and the other being a web layer.
The end result goal is to have a fully functioning WAR in the Web project's target folder, that I can simply deploy into a Tomcat.
Here is where I am not clear:
- Both the Service project, and the Web project need to use Spring. The Service project needs to use Spring simply for it's dependency injection purpose. I need to take a simple Dog class, and auto-inject it into the DogService object. That's all working fine.
- Then I need to auto-inject a DogService object into a Dog controller. The Dog controller exists within the Web project in the multi module structure. This is also working fine, because I have declared a dependency in the Web project for the Service project, therefore all Service JARs are included in the final built WAR, from the web project.
1) Is there a way to simply declare a Spring dependency for both child projects without having to declare the dependencies in each child POM.xml? I just want to make sure I'm not duplicating resources. I believe the way to do this is just to declare the dependency in the Parent POM.xml.
2) If I do #1 above ^, is this the optimal way of creating the project? In essence, the WEB module is the one that contains all the final jars, and in essence it's almost as if the SERVICE project doesn't even exist in Tomcat. As far as Tomcat 'knows', all there is, is a bunch of JAR files containing classes, some of them having been written in my WEB module, and some of them having been written in the SERVICE module, all of which is irrelevant to the production/Tomcat environment. True or false?
Thanks!
Is there a way to simply declare a Spring dependency for both child projects without having to declare the dependencies in each child POM.xml? I just want to make sure I'm not duplicating resources. I believe the way to do this is just to declare the dependency in the Parent POM.xml.
Maven is quite intelligent about dependency management and will not "duplicate" resources--it caches each dependency once* and manages the classpath so that all of the projects that you work with share the same jars. In general, declare dependencies in the modules where they're needed; don't clutter up modules or especially parents with random pieces just to avoid occasionally re-specifying a dependency. This is like hauling your boat trailer on your daily commute because you occasionally go to the lake.
Keep in mind that dependencies are transitive, so that if service-module depends on spring-web (does it really, or are you spamming dependencies?), if web-module depends on service-module it will pull in the dependency as well without having to repeat yourself.
If I do #1 above ^, is this the optimal way of creating the project?
No, it isn't. Be minimalist about your dependencies: If you need it, include it, but don't add dependencies "defensively". This will just bloat your deployment and slow down builds, along with adding opportunities for problems like version mismatches.
As far as Tomcat 'knows', all there is, is a bunch of JAR files containing classes, some of them having been written in my WEB module, and some of them having been written in the SERVICE module, all of which is irrelevant to the production/Tomcat environment. True or false?
Mostly false. In a war, your top-level project (web-module) has its classes directly in the archive, and dependencies are embedded as jar file inside it. Tomcat does not distinguish between service-module and your Spring and other dependencies, however.
Better still would be using Spring Boot's standalone jar and embedded container features--Boot will take care of packaging up the jars you need into a single runnable file that doesn't need external support.
*Release dependencies only, but snapshots aren't relevant here.

Should jars have "provided" dependencies?

We are building an ear that is going to run on a Websphere where j2ee.jar is provided.
Now we have the situation that an ejb (call it ejb.jar) depends on another jar (call it util.jar) which depends on j2ee.jar.
If mark j2ee.jar in the pom of util.jar as "provided", the ejb.jar won't build because provided is not transitive. If we mark it as "compile", it may become a compile dependency of the ear, unless we overwrite the scope.
What is the best approach? Should util.jar have provided dependencies, even if it is just a humble jar? Or should jars only have compile dependencies?
JARs can have provided dependencies... but the user having a dependency on it needs to make sure that this dependency is actually going to be provided at run-time. Since provided dependencies are not transitive, they also need to make sure that they do not depend on it for compilation; but if they do, the best practice would be to declare it explicitly with the compile (or provided) scope, and not rely on some form of transitivity (look at the analyze goal of the Dependency Plugin, which, for example, lists used, but undeclared, dependencies).
Provided dependencies in JARs can be useful when creating executable JARs. Consider the building of an uber-jar (a JAR with the classes all of its dependencies included in it): you may want to say that a specific dependency shouldn't end up in the uber-jar, because the container launching it will provide it at run-time.
Also, a JAR may need a dependency to compile its code, but does not actually need it to run; as example, consider Maven plugins which declares maven-plugin-annotations as a provided dependency because they only need the annotations to be built.
Final point, there are JARs that have a good idea in which context they are going to be used: Spring WebMVC, for example, certainly depends on the Servlet API to compile, but at run-time, it knows it's going to be used in a Java EE context, and that the Servlet API will be provided by the Java EE server.
As a rule of thumb though, apart from the cases above, you probably don't want to have provided JAR dependencies inside of a JAR project: it should be up the client to decide whether some compile-time dependencies of yours are going to be provided for their specific case, and let the client override the scope. As a library writer, you don't really know how your library is going to be used.
In your specific case, since ejb.jar actually needs j2ee.jar to compile, it would be best to declare that dependency with the compile, or even with the provided scope in your case, regardless of what scope util.jar has set for j2ee.jar. (I'll note that it's weird for an utility JAR to have a dependency on what appears to be a JAR from Java EE web application classes.)

Maven dependency order check

I need to check the Maven dependency injection order automatically. In a Maven module I take two dependencies with the same classes name and package. One dependency should always have priority on the other one, this mean it have to be declared first because of the order of dependencies injection of Maven.
It's possible to verify it with the dependency tree but manually, I wish there is a way to check this automatically.
Do you know if it is possible to do this with Maven?
First of all, "dependency injection" is something completely different and unrelated: managed magical mechanisms to pass needed objects from "outside" when constructing objects.
Maven just compiles code with dependency jars in the classpath. Any variant of the monkeypatched classes should allow your code to be compiled identically, so (to minimize breakage) you should avoid duplicate or conflicting Maven dependencies.
Reliably loading your replacement classes at runtime when Maven is no longer involved is an entirely different problem, whose solution depends on how your application is packaged and executed. For example, the order of jars in a typical classpath list should be reliable, and most application servers offer ways to specify and override with one another various global and application-specific classpaths.

Is there a dynamic java class level Ivy-like resolver?

This is more a question about what's out there, and future directions about resolving tools such as Ivy. Is there anything that can mention class-level dependencies for packages, rather than package level dependencies?
For example, let's say I have an apache-xyxy package, that comes with an ivy.xml that lists all it's dependencies. But suppose I only use class WX in apache-xyxy, which doesn't require most of those dependencies. Couldn't a resolver be intelligent and identify that class WX can only possibly invoke the set of other classes (AB, DC, EF), and none of those classes use any of other dependencies, to create a minimal subset of required dependencies? This would be easier and safer than cherry picking to remove some package dependencies that aren't needed because of the specific classes used in that package, and also prevent breaking down several larger packages into smaller ones just for this reason.
Then, if I later decided to use class GH from apache-xyxy, I could do an ivy resolve, and it would dynamically bring in the additional required libraries.
When packaging compiled java code for distribution it's common practice to bundle Java "packages" together. It's also quite possible (but silly) to split a java package across multiple jars. Large frameworks (like Spring) have lots of sub packages in different jars so that users can pick and choose what they need at run-time..... Of course the more jar options one has, the more complex it becomes to populate the run-time classpath...
The keyword here is "run-time".... Tools like Apache ivy and Apache Maven are primarily designed to manage dependencies needed at build time....
Apache Maven does have a "runtime" scope, for it's dependencies, but it's limited to a single list of jars. Typically this scope is used for deciding which jars are needed for testing and populating the lib directory of a WAR file.
Apache ivy has a similar more flexible mechanism called "configurations". It's possible to create as many runtime configurations as you need, and these can be used to decide which jars are downloaded by ivy.
So while it would appear ivy has the answer, I've rarely seen ivy used when launching programs (The one exception is Groovy's Grape annotations)
So what, you might ask, is the answer?
The future of "run-time" classpath management is either OSGI or project jigsaw. I'm more familiar with OSGI where special dependency indicators are added the the jar file's manifest, stating what it's dependencies are. The idea is that when a container loads a jar (called a "bundle") it can check and see whether the other dependencies are already loaded. These dependencies can be retrieved and loaded from a common repository. This is fundentally different way to launch java. Traditionally each application is loaded onto it's own isolated classpath.....
Time will tell if either project catches on. In the meantime we use Apache ivy and Apache Maven to build self-contained and possibly over-bloated WAR (EAR, etc) packages.

Categories

Resources