Maven shade - repackage dependecy jar with custom configuration - java

I have a common service which is packaged as a jar with all it's dependencies.
Consumer1, consumer2, consumer3 provides different configuration for Common_service.
What is the best way to repackage common_service with all it's jar content and in addition, bundle the configuration with it.
Final output, on Consumer1 would give :
Consumer1-shaded.jar (without common-service)
Consumer1-Common-service.jar (only common-service with custom configuration)
Consumer2 would give :
Consumer2-shaded.jar (without common-service)
Consumer2-Common-service.jar (only common-service with custom configuration)
I tried maven shade to repackage common_service, but I need to explicitly include all the dependencies of common service in consumer., Why should the consumer be aware of the common service contents ? Is there any direct way to take the jar, add config and repackage ?

To get what you want, probably your best bet is to have four maven modules. The common_service module would no longer produce a shaded jar, just a regular jar. The consumer_1 module would include the configuration files and have common_service as a dependency, and would produce a shaded jar. The consumer_2 and consumer_3 modules would be set up similar to the consumer_1 module.

Related

What does gradle import fom a war dependency and how can I control/manipulate the war contents?

I added this artifact which is a war to my gradle project dependencies.
I need to extend some classes, and use a modified servlet contexts from it.
I was expecting the war to be imported as is then I would use gradle tasks to manipulate to include the jars to dependencies, copy static resources to correct classpath etc.
But gradle actually added a bunch of jars to dependency.
Im not sure if gradle scanned recursively all paths for jars and poms or probably just the jars under the WEB-INF/classes folder in the war.
I can assume probably not the poms repositories as stated here.
Im I correct is assuming the jars in the WEB-INF/lib folder in the deflated war were not imported? its hard to tell as there are a lot of shared dependencies between my project and the war in question
Then whats the best way to declare a dependency on a war in the maven repo/jcenter if I need to extend and modify as I described at the top?
UPDATE:
I am now trying to use answer below and this solution https://discuss.gradle.org/t/how-to-add-an-artifactory-war-as-a-gradle-dependency/19804/2
, This only worked after moving the directory with the copied jars outside the buildDir
my build.gradle
configurations {
warOnly
}
dependencies {
// not working implementation fileTree('$buildDir/explodedWar/WEB-INF/classes')
implementation fileTree('anotherDir/explodedWar/WEB-INF/classes')
// implementation fileTree('$buildDir/explodedWar/WEB-INF/lib')
implementation fileTree('anotherDir/explodedWar/WEB-INF/lib')
warOnly 'ca.uhn.hapi.fhir:hapi-fhir-jpaserver-starter:4.2.0#war'
}
tasks.register("explodeWar",Copy) {
from zipTree(configurations.warOnly.singleFile)
// into "${buildDir}/explodedWar"
into "anotherDir/explodedWar"
}
compileJava {
dependsOn explodeWar
}
By declaring a dependency on a WAR, Gradle will simply add it to the list of files for the matching configuration. So if you add a WAR in implementation, it will simply be on the compileClasspath and runtimeClasspath without any processing.
So for sure Gradle will not transform your WAR dependency in a dependency on the JARs it contains.
If you want to use a WAR to copy and modify some of its content before repackaging it, you can use an isolated and custom configuration to resolve it from a remote repositories. Then you will define a Gradle task that will take the files of that configuration as the input and do the required processing on the WAR. Note that the task could also be the starting point of a series of tasks manipulating the WAR to one output, then that output to another one, etc ...
configurations {
warOnly
}
dependencies {
warOnly "com.pany:some-war:1.0"
}
tasks.register("copyWar", Copy) { // Register a copy task to modify the WAR
from(zipTree(configurations.warOnly)) // I did not run this, so you may have to get to the single file instead
// Regular copy configuration to decide a destination, perform on the fly changes, etc ...
}
It took some trail and error but there is better way. When using the dependency:
providedCompile 'ca.uhn.hapi.fhir:hapi-fhir-testpage-overlay:6.0.1'
Gradle will download a war file and place it you your classpath. However providing a classifier will help here. The following dependency will get the jar file.
providedCompile (group: 'ca.uhn.hapi.fhir', name: 'hapi-fhir-testpage-overlay', version:'6.0.1', classifier: 'classes')

Java Gradle find out dependency's jar file name

I have a java gradle project. I have a dependency.
dependencies {
compile project(":mymodule")
compile 'org.springframework:spring-context:4.1.2.RELEASE'
}
Where can I find and use exact jar file name of both my custom module and spring dependency jar to process it further in composing application's libs, folders, etc?
Stick this in a new task:
project.configurations.compile.each{ println it}
Or, for just one specific dependency:
println project.configurations.compile.find {it.name.startsWith("something") }
However, if you're looking to create distributable packages including dependencies, you really should look into the gradle application plugin.

Maven modules and Spring test resources

I have a Maven project made up of several modules. Some of the modules depend on the other modules for example Module C <- Module B <- Module A. Module C depends on Module B which depends on Module A.
In each module, I have Spring config files in main/resources and test/resources, those under test are for unit testing, while the those under main are for release/production. Each config file is self contained - Module B contained only its Spring config (file names are like so foo-B.xml, foo-A.xml)
However, when I need to test Module C, I need to reference Module B's Spring config under test/resources, but what is included is Module B's main/resources config file. This presents a problem because the production file has references to JNDI datasources where test one does not.
How can I get Maven or Spring to reference the test configuration file from the module dependency?
Maven separates the source classes & resources from the test classes & resources. You may configure Module B to create a test jar using the maven-jar-plugin test-jar goal. Then, you may have Module C reference Module B's test code as a dependency.
<dependency>
<groupId>com.myCompany</groupId>
<artifactId>moduleB</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Alternately, you can create a regular Maven project including only the test code you'd like to share, then include that as a test dependency where needed. This idea is described in the maven jar plugin's usage docs.
I'm not sure this can be done. Maven deliberately does not include test resources in artifacts. If I were in your place, I would duplicate the test resources in module C. Presumably, you're not testing the same things in both modules, so hopefully it won't cause a bad case of copy&paste/dual-maintenance.
As an aside, I try to avoid having "production" data sources and "test" data sources. Use the same JNDI name for both, but have the JNDI provider configured to point to test or production based on the circumstance. For example, all of our web servers have the same data sources defined, but the JDBC urls are different for dev/qa/prod. For your unit tests, use something like simple-jndi to simulate a JNDI environment.

maven - separate modules for interfaces and implementation with Spring

We are working on Mavenizing our java project and we would like to setup a clean separation between interfaces and implementations for each module.
In order to do so, we want to split each module into two sub-modules one for interfaces and data objects used by them and another for implementations.
For example:
+commons
+commons-api
+commons-impl
The POMs of the modules will be configured such that no module depends on the impl sub-modules. This way no code from one module will be able to "see" implementation details of another module.
What we are having trouble with, is where to put our spring XMLs.
In our project we automatically import spring XML files using wildcard import like
<import resource="classpath*:**/*-beans.xml"/>
This way the location of Spring XMLs doesn't really matter at runtime, as all the modules get loaded into the same class loader and, the strict one way dependency rules in the POMs don't apply.
However, during development we want the IDE - we use Intellij IDEA - to recognize implementation classes referenced from the spring XMLs.
We also want IDEA to recognize beans defined in other modules.
If we put the spring XMLs in API sub-modules - they won't "see" the implementation classes in the impl sub-modules.
If we put them in the impl sub-modules, their beans won't be "seen" from other modules.
It is probably possible to configure the IDEA project to recognize spring XMLs from modules on which there is no dependency, but we prefer for our POMs to hold all the project structure information and not rely on IDEA project files.
We considered creating a third sub-module just to hold Spring XMLs (and perhaps hibernate xmls as well). For example:
+commons
+commons-api
+commons-impl
+commons-config
The external modules will depend on both commons-api and commons-config and commons-config will depend on both commons-api and commons-impl, with the dependency on commons-impl marked as "provided" (to prevent transitive resolution).
This however seems like a complex and awkward solution and we feel that there must be a better - simpler way to achieve interface/impl separation with Maven and Spring.
What you need is a runtime dependency scope:
runtime - This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
(https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
Define a runtime dependency from one impl module to another impl module where you use the impl classes in the *-beans.xml config. Intellij will correctly recognize this in spring configuration files, but won't auto complete them in code (but it will do that in test code).
Also if anyone used the classes in the code, compilation through maven would fail, because the runtime dependency is not on a compile class path.
You can achieve decoupling of api and impl like this:
+ commons (pom)
+ pom.xml <--- serves as a parent aggregator (see below)
+ commons-api (jar) <--- contains models, interfaces and abstract classes only
+ commons-impl (jar) <--- depends on commons-api
+ commons-config (jar) <--- depends on commons-impl only (no need to depend on commons-api as it is brought in transitively)
+ external-project (war or jar) <--- has commons-config as a dependency
Parent aggregator pom (specify build order):
<modules>
<module>commons-api</module>
<module>commons-impl</module>
<module>commons-config</module>
</modules>
The config module can be omitted if it only contains spring application context configuration. The app configuration xml should be in the classpath and folder structure of the module that contains the artifact that you are deploying. So if you are building a war artifact, the app context should be in there.
The only configuration that should be in your commons module would be in a test package of your impl module.
In short you want Idea to override maven dependency graph but avoid keeping this configuration in idea project files?
One option is to group implementation dependencies in a maven profile. This profile would not be enabled by default but you should be able to mark it as active under idea.
Two ideas come to mind:
You will have one (or more) modules where all the modules (api+impl) are dependencies, you could place your spring configuration files there.
Place the spring configuration files in the api modules and declare a dependency on the impl module with scope provided this way the implementations will be known, while there is no dependency of the api for the deployment.
commons-impl at runtime scope in external modules
commons (pom dependencyManagement) =>
+commons-api (compile)
+commons-impl (compile)
+commons-config (compile)
commons-impl (pom dependencies) =>
+commons-api (compile)
+commons-config (compile)
external modules (pom dependencies) =>
+commons-impl (runtime)
+commons-api (compile)
+commons-config (compile)
keep modules number as little as possible;
This speeds up project build time and simplifies its layout.
keep modules structure as plain as possible: single root + all sub modules in the same folder, e. g.:
pom.xml
commons-api/
commons-runtime/
module-a-api/
module-a-runtime/
...
This simplifies navigation across the project, when modules number is really high (>50)
provide runtime-scoped dependencies to the runtime modules only when they are required;
This keeps your architecture clear. Use mocks instead of explicit dependency to another runtime module.
keep your api spring contexts in api modules, define your public beans as abstract bean + interface;
keep your implementation contexts in runtime modules, override api beans with your implementations via spring profiles (use <beans profile="default").
Result: simple, transparent layout and design; full ide support; no explicit dependencies on runtime module internals.

How can I force maven to leave the version number out of dependency file names?

I'm using maven to build a ".ear" project that resolves dependencies from a maven repository, and then packages them into an ear (that's probably a redundant sentence...).
When the dependencies show up in the ear file, they're named according to this format:
<artifactId>-<version>.<type>
I'd like them to be named:
<artifactId>.<type>
Can someone point me in the right direction?
If you're using the maven-assembly-plugin to build your ear, you can use the outputFileNameMapping property in your descriptor: http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html#class_dependencySet
However, you're probably better off using the maven-ear-plugin, in which case you can customize the bundleFileName, as described here.
Set the finalName property. See http://maven.apache.org/plugins/maven-assembly-plugin/assembly-mojo.html for more details

Categories

Resources