-1

I have a project A that depends on a project I that contains interfaces implemented by a third project, B.

I want project B to be dinamically plugged in project A's pom.xml at compile time, without changing A's pom.xml and providing properties to Maven by the command line (example

mvn package -Dmodule.artifactId=[B_ARTIFACTID] -Dmodule.version=[B_VERSION]

) where B_ARTIFACTID and B_VERSION refers to project B.

The aim is to tag a version of project A and, throught the interfaces contained in I, use the implementation contained in a fourth project C that implement I with the same version of project A, just changing the command line that builds it.

I know this is possible using profile properties, but at the time project A will be tagged it will not resolve dependency, how to fix this without using a default dependency?

B and C depends on a project identified by:

<groupId>project</groupId>
<artifactId>I</artifactId>
<version>0.1.0.0</version>

Project A

<dependencies>
  <dependency>
    <groupId>project</groupId>
    <artifactId>I</artifactId>
    <version>0.1.0.0</version>
    <dependency>
      <dependency>
        <groupId>project</groupId>
        <artifactId>???</artifactId>
        <version>???</version>
        <scope>runtime</scope>
        <dependency>

EDIT: i said that i don't want to do it with properties, because it will not resolve dependency at the time i tag project A.

A. Coluzzi
  • 13
  • 4
  • 2
    You shouldn't do that. 1st, the `artifactId` is crucial. You can't implement anything in `Project A` that depends on that specific artifact as long as its unknown/not loaded. 2nd: any version difference can break your whole application. Assuming you make a typo with the version (or the artifactId), you could be searching the error for ages because you don't know for sure what the reason might be. But if you really want to have this issues, read up on [this question](https://stackoverflow.com/questions/10209686/maven-dynamic-specification-of-dependencies) – XtremeBaumer Feb 22 '19 at 08:45
  • Possible duplicate of [Maven: dynamic specification of dependencies](https://stackoverflow.com/questions/10209686/maven-dynamic-specification-of-dependencies) – XtremeBaumer Feb 22 '19 at 08:47

2 Answers2

1

So A compiles fine against I; there is a dependency in A to I.

The implementation of I in C could be added as jar to A with either:

  • <scope>runtime<scope> or
  • <scope>provided<scope> if where the jar A is run, there is a jar C.

Then there is the question of no dependency.

If the jar C uses java SPI (Service Provider Interface), it can let A do a lookup on some interface:

  • I

    package net.i.api; interface Api { ... }
    
  • C

    package net.c.api; class ApiImpl implements Api { ... }
    
    • A text file /META-INF/services/net.i.api.Api:

      net.c.api.ApiImpl
      
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • How is possible to dynamically add dependency of B or C in A? The project A doesn't know during its development how many implementation of I exists, and we don't want to edit pom.xml just for release of project A-b (A with dependency B) or A-c (with dependency C). – A. Coluzzi Feb 22 '19 at 09:24
  • With Java SPI one can add C to the classpath of the application (no dependency), and detect one or more implementing classes of I's interfaces. This was for instance done with the Xerces and Xalan implementations of the XML api. Mind, the classpath can also be a directory of jars – Joop Eggen Feb 22 '19 at 09:35
  • So it is not possible to build A in a jar that contains B too, without insert B in the pom.xml. We need that to create a sort of pluggable module (A). Is also required that A-b module (A with dependency of B in it) is contained in a single jar – A. Coluzzi Feb 22 '19 at 09:43
  • You can add the B jar as distribution file in the pom, without dependency/artifactId. – Joop Eggen Feb 22 '19 at 09:46
  • How can I add this dependency? We are trying to find a way to add this dependency during CI/CD passing some parameters (groupId, artifactId, version) without edit pom.xml. Is it possible? – A. Coluzzi Feb 22 '19 at 09:54
  • Sorry I cannot help there; you could have a separate maven module, and also profiles were already mentioned. – Joop Eggen Feb 22 '19 at 10:06
1

Maybe you are not taking the right approach. This sounds to me like trying to statically link your program against one library or another - Java does not work that way.

Java is all about dynamic linking. Nothing prevents you from compiling A and I together without referencing at all B or C - it just compiles, but it will throw an exception at some time during execution since it has no implementations for the interfaces in I.

You should just implement some kind of Abstract Factory, returning I objects after looking for a proper implementation. The criteria of this factory to take decisions may be taken from some properties file, or a deep dive in reflection/annotated classes, etc.

https://en.wikipedia.org/wiki/Abstract_factory_pattern

Scanning Java annotations at runtime

When you distribute your app, you just package your A and I jars with the implementations: B, C, or whatever you want to extend your aplication in the future (D, E, etc.) Once in run time, your AbstractFactory will have to take the decision based on application setup and available implementations.

As an example, think of Windows Media Player (I know, different technology but same idea) and how it looked for codec implementations, and how once we downloaded and registered them it could just play the clips without any modification to the software itself.

Jorge_B
  • 9,712
  • 2
  • 17
  • 22
  • We are trying to find a way to have a single jar with A, I and a single implementation of I. We are using SPI, so we need to integrate during "mvn package" choosing between C or B because in production we must release a single jar – A. Coluzzi Feb 22 '19 at 09:33
  • Then I should insist in my proposal: decouple dependencies with an AbstractFactory, compile everything separately, prepare your CI/CD pipeline to build different deliverable packages, each one with the proper implementation (B, C, etc.) and let every production setup to find its implementation classes in run time. – Jorge_B Feb 22 '19 at 09:47
  • Maybe the problem here is to assume everything must be solved in A project pom.xml. Probably that pom.xml should not shoulder too many responsabilities appart from building A project, with a dependency to I. The building of the different deliverables sounds to me like a different problem to be solved at a different level - maybe in CI pipeline with another pom? – Jorge_B Feb 22 '19 at 09:49
  • This is our goal, but we hope to find a way to integrate proper implementation without edit "pom.xml" but just passing some parameters (artifactId, groupId, version) . Have you some idea , maybe in maven lifecycle o something else? – A. Coluzzi Feb 22 '19 at 09:52
  • My proposal here is not to try to fit your needs in the A project maven lifecycle, but to bring that problem to a higher level. A way to achieve this is by decoupling the dependencies to A -> I, and nothing else. Then an AbstractFactory (maybe implemented in I project) will look in runtime for an appropriate implementation. Now your implementations are B and C - this architecture will protect you in the future when you need to extend it with D, E, etc. Your CI pipeline will be held responsible for putting the necessary artifacts into each production package. – Jorge_B Feb 22 '19 at 10:16