Expand my Community achievements bar.

Learn about Edge Delivery Services in upcoming GEM session
SOLVED

Maven Dependecy Issue

Avatar

Level 2

I have created two projects based on maven archetype 22. 

Project A and Project B.

 

In project A - I have created an interface HelloWorld.java and implemented it - HellowWorldImpl.java - in this implementation - have created 'sayHello' method with custom log message - "Message from sayHello method - version 1.0.0"

In project B - I have created an interface HelloService.java and implemented it - HelloServiceImpl.java

Added project A's dependency with version 1.0.0 in Project B's pom.xml and consumed HelloWorld service by calling 'sayHello' method.

After clicking on project B bundle "Refresh Package Imports" in felix console manager - observed "Message from sayHello method - version 1.0.0" in the logs.

 

Later increased version of project A from 1.0.0 to 2.0.0 and updated custom log message to "Message from sayHello method - version 2.0.0". However I didn't change project A's version in the project B's pom.xml. i.e. retained 1.0.0 version of Project A.

Now upon refreshing the package imports of Project B - I was expecting old custom log - "Message from sayHello method - version 1.0.0". But it showing new message - "Message from sayHello method - version 2.0.0"

 

Ideally I am referring to 1.0.0 version of  Project A in Project B's pom.xml - so I should get - "Message from sayHello method - version 1.0.0".

 

Please help me clarify this behavior.

 

Thanks in advance

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

There's a difference between build-time dependencies and runtime-dependencies. And as a second layer of confusion there is a difference between bundle/project versions and package versions.

 

Let's first deal with the build time. At build time you specify the dependencies via maven coordinates. For example you specify that you want the uber-jar artifact in version 6.5.5. Packed in these uber.jar are API definitions at a certain state. These API definitions also contain version information at java package level. During the build process the bnd-maven-plugin (or the maven-bundle-plugin, depends a bit on the version of your archetype, but basically they are doing pretty much the same) extracts these package informations of the APIs you are using and writes these version information into the MANIFEST.MF (which is then part of the bundle).

 

When you now deploy this bundle into AEM (or any other OSGI container), the runtime reads these dependency information and tries to resolve them; for that it scans the packages exported by other bundles and checks if there is a matching package export within the correct version range. If such a package is found, everything's fine and the dependency is resolved. If you have any package which cannot be resolved, the bundle won't get active.

 

So, to answer your question: On runtime any maven or bundle version numbers are irrelevant. Only the package versions are relevant. In your case the package version has not been updated (it's always 1.0), so it doesn't matter what bundle version your bundle B has, the current version is bound because the dependency is still resolved. At https://bnd.bndtools.org/chapters/170-versioning.html there is some description how you can define the version number for your packages. If you use the bnd-baseline-maven-plugin it can tell you if you should really bump a version number.

 

So, when are versions relevant at all? Versions are only relevant, when they are describing an API (that means, we are talking about java interfaces in the first place). You can implement the evolution of an API (most notably: Incompatible changes) via such versions, so you can express: As a consumer I need at least version 2.1 of the API; if your OSGI container does provide this API only in version 1.9, your bundle will not get active and you can spot that problem immediately. In most cases it makes sense to have both API and implementation in the same bundle, so this situation is very intuitive, and API and implementation will always match.

 

But of course there are other situations, where it _could_ make sense to split implementation and API into separate bundles. But these are quite rare and make only sense where there is a benefit in decoupling them (mostly from a maintenance point of view).

 

Some final remark to the runtime aspect: Technically OSGI allows you to have a same java package being present in 2 different versions. Right now the AEM support for this scenario is not existent (I don't think it's tested, although the OSGI runtime should support it), so it's better to have a java package only in 1 version exported. If you need to have a newer/older version of a package provided by AEM (which is of course not part of the AEM surface, but rather some 3rd-party lib), you can embed that library, so your dependencies are not resolved by OSGI by using references to other packages, but instead to libraries residing in your own bundle.

 

Hope that helps,

Jörg

 

 

 

 

 

 

 

 

 

View solution in original post

2 Replies

Avatar

Correct answer by
Employee Advisor

There's a difference between build-time dependencies and runtime-dependencies. And as a second layer of confusion there is a difference between bundle/project versions and package versions.

 

Let's first deal with the build time. At build time you specify the dependencies via maven coordinates. For example you specify that you want the uber-jar artifact in version 6.5.5. Packed in these uber.jar are API definitions at a certain state. These API definitions also contain version information at java package level. During the build process the bnd-maven-plugin (or the maven-bundle-plugin, depends a bit on the version of your archetype, but basically they are doing pretty much the same) extracts these package informations of the APIs you are using and writes these version information into the MANIFEST.MF (which is then part of the bundle).

 

When you now deploy this bundle into AEM (or any other OSGI container), the runtime reads these dependency information and tries to resolve them; for that it scans the packages exported by other bundles and checks if there is a matching package export within the correct version range. If such a package is found, everything's fine and the dependency is resolved. If you have any package which cannot be resolved, the bundle won't get active.

 

So, to answer your question: On runtime any maven or bundle version numbers are irrelevant. Only the package versions are relevant. In your case the package version has not been updated (it's always 1.0), so it doesn't matter what bundle version your bundle B has, the current version is bound because the dependency is still resolved. At https://bnd.bndtools.org/chapters/170-versioning.html there is some description how you can define the version number for your packages. If you use the bnd-baseline-maven-plugin it can tell you if you should really bump a version number.

 

So, when are versions relevant at all? Versions are only relevant, when they are describing an API (that means, we are talking about java interfaces in the first place). You can implement the evolution of an API (most notably: Incompatible changes) via such versions, so you can express: As a consumer I need at least version 2.1 of the API; if your OSGI container does provide this API only in version 1.9, your bundle will not get active and you can spot that problem immediately. In most cases it makes sense to have both API and implementation in the same bundle, so this situation is very intuitive, and API and implementation will always match.

 

But of course there are other situations, where it _could_ make sense to split implementation and API into separate bundles. But these are quite rare and make only sense where there is a benefit in decoupling them (mostly from a maintenance point of view).

 

Some final remark to the runtime aspect: Technically OSGI allows you to have a same java package being present in 2 different versions. Right now the AEM support for this scenario is not existent (I don't think it's tested, although the OSGI runtime should support it), so it's better to have a java package only in 1 version exported. If you need to have a newer/older version of a package provided by AEM (which is of course not part of the AEM surface, but rather some 3rd-party lib), you can embed that library, so your dependencies are not resolved by OSGI by using references to other packages, but instead to libraries residing in your own bundle.

 

Hope that helps,

Jörg