M2E: Version is duplicate of parent version - Why is this a warning? - eclipse

I have several Maven projects that each have some common functionality or at least common configuration/dependencies. I extracted this in to a common pom.xml, and then modularlized several facets, for example persistence, Spring related dependencies, and so on - all in their own modules which inherit from this parent POM.
Right now, "Common" is version 1.0.0 and I have "ProjectA" that I wish to inherit from it. I receive the warning:
Version is duplicate of parent version
I don't fully understand why this is a warning. I thought I had the option of omitting the version from my project POM in order to inherit the version. (I do this for common modules - for example, common-spring adds additional common dependencies for Spring apps, and in fact, ProjectA actually inherits from common-spring.)
Isn't it just that - an option? If I change my ProjectA version to 1.0.1 or 2.0.0 all is well.

Newer versions of m2e (since 1.1) now allow you to disable this warning.
Preferences > Maven > Warnings > Disable "Version is duplicate of parent version" warning
Original bug report: https://bugs.eclipse.org/bugs/show_bug.cgi?id=356796

It´s just m2e trying to be clever because the version element (like group id) sometimes can be redundant and be can be inherited from the parent POM, so it would be safe to remove this element from your child POM.
But sometimes this is not a redundant information, like when the parent and the child project have different life cycles, and m2e should allow this warning to be disabled. Unfortunately there is no way to do this yet: http://dev.eclipse.org/mhonarc/lists/m2e-users/msg01961.html
UPDATE: As Duncan says bellow, in newer versions you can disable this warning.

If it really annoys you, use a property to supress the warning with some cunning sleight of hand:
<version>${api.version}</version>
<properties>
<api.version>0.0.1-SNAPSHOT</api.version>
</properties>
but all you'll really be doing is moving the warning to the console output:
[WARNING] Some problems were encountered while building the effective model for [project]
[WARNING] 'version' contains an expression but should be a constant.

Related

How to create a package that is most likely not to cause versioning problems?

I created a NuGet package with an empty logger and my package depends on Microsoft.Extensions.Logging.Abstractions.
My PackageReference line and my dependency in the .nuspec file are set to 1.0.0 with no special syntax which I understand means >=.
My empty logger works just fine with this version and I thought using the lowest working version of the abstractions lib would make my package easier to consume by applications which are likely to have greater versions.
However, when I've referenced my package from an xUnit test project I have a red compiler error CS1705.
My test project references two packages:
The project its testing, which is an ASP.NET Core Razor Pages site that in turn references the same logging abstractions package which is included in Microsoft.AspNetCore.App 2.2.0 metapackage.
My empty logger package, which, in turn references the logging abstractions 1.0.0.0 as I have described.
Compiler error from the test proj says:
Assembly (Razor Pages proj) uses (Abstractions 2.2.0.0) which has a higher version than referenced assembly (Abstractions) with identity (Abstractions 1.0.0.0).
My package can use the higher version so what am I missing?
Edit
Here's a high fidelity diagram ;)
T is "xUnit Proj".
W is the "Website Proj" under test.
E is the empty logger package (Evoq.Instrumentation on nuget.org)
A is metapackage Microsoft.AspNetCore.App 2.2.0
L is Microsoft.Extensions.Logging.Abstractions
There's the nearest wins rule, which I think means that the dependency from T to L via E would win and version 2.0.0 would be used but I'd expect a package downgrade warning not a hard compiler error.
Nearest wins: https://learn.microsoft.com/en-us/nuget/consume-packages/dependency-resolution#nearest-wins
Edit 2
It just occured to me that T > W is a project reference. So maybe that's short-circuiting the NuGet resolution. I'll add a ref from T to A directly and see if that solves it.
I forgot T > W is a project reference. So I think that was short-circuiting the NuGet resolution I was expecting to take place.
I added a ref from T to A directly and that solved it.

Understanding eclipse maven dependency hierarchy

I want to understand the dependencies for a multi-module maven project and for that referred to eclipse dependency hierarchy.
I did understand fairly, however some of the things I am not able to understand at all.
Below is the screen shot.
The things which I didn't understand are:
--> managed from 1.0.2 [Compile}
--> managed from 1.0.2 (omitted for conflict with 1.0.0) [Compile]
I did search online but I got information in traces. Can anyone help me understand what they mean in easy to understand?
Thanks.
Maven builds a flat classpath from the dependency tree each for compiling ([compile]), for testing, and for running.
In a flat classpath, unlike OSGi, a dependency can only exist in one version. In your cropped screenshot, there is on the second level among other things:
kafka-streams 1.0.2 and
kafka-clients 1.0.0.
kafka-streams 1.0.2 requires kafka-clients 1.0.2 which conflicts to kafka-clients 1.0.0. Therefore kafka-streams 1.0.2 is omitted for conflicts with 1.0.0 even if the version 1.0.2 is required here ("managed from 1.0.2").
More detailed:The classpath which is used to compile or run a plain Java application is flat: all required libraries are globally specified as an ordered list. It is not possible to use a library of a specific version for one package and for another package the same library in a different version.In Maven dependencies builds a tree: each dependency might have its own dependencies. Maven maps the tree of dependencies to the classpath, an ordered list of libraries. If in the Maven dependencies tree the same library exists in different versions, it is not possible to create a flat classpath. This is a conflict.This conflict is resolved by picking one version and omitting all other versions. At the place where the picked version is used instead of the required version, (managed from <required but not picked version>) and (omitted for conflict with <picked version to use instead>) is displayed.In addition, Maven can create different classpaths to compile, to test or to run a Java application via so-called scopes. The [compile] scope is the default scope for using a library in all tasks: compiling, testing and running.
Make sure that the versions specified in the pom.xml file are compatible with each other (which is not yet the case in your screenshot): you have to upgrade kafka-clients from 1.0.0 to 1.0.2 (or downgrade the other libraries).

Why does Eclipse turn a maven runtime dependency into a compile dependency?

I have a maven project imported into Eclipse Oxygen. Eclipse reports no compile issues (Alt + F5). When I run maven from the command line I get
[ERROR] /home/dean/src/TAP3UIs/TAP3Desktop/src/main/java/com/ms/tap3/controller/RequestAccessController.java:[8,30] package com.google.common.base does not exist
That package does exist in my .m2/repository in guava-15.0.jar. I can also see it in Eclipse mvn dependencies. When I check the mvn dependency:tree for the project I see
[INFO] | | | +- com.google.guava:guava:jar:15.0:runtime
It is a runtime transitive dependency on the command line, which explains why it doesn't compile on the command line. Somehow Eclipse has turned a transitive dependency from runtime to compile.
Does anyone know why this happens and how I make Eclispe m2e respect the scope of the transitive dependencies?
Currently, neither JDT nor m2e support multiple classpaths per project which is required to support different scopes.
See: Eclipse bug 486035 - Different classpath containers for different scopes
Update:
Since Eclipse Photon (4.8) which was released in June 2018 this is now supported. See Eclipse bug 526858 and my video showing this in action.
The main point is this: If you import external classes in your source code, you must set them as compile dependencies, and never trust the fact that they might already be transitive dependencies (because, since they are transitive, you have not direct control over them, so in a future version they might diseappear as well).
What is happening is this:
You need some classes from com.google.common.base package, so you need to set com.google.guava:guava:jar:15.0 as a dependency.
Instead, you didn't because you realised it was already a transitive dependency, but you missed the fact that is a runtime dependency.
Eclipse M2 does not distinguish the different Maven's standard classpaths, so it treats all dependencies as if they were of "compile" scope. So Eclipse includes guava-15.0.jar in the compilation and the project is compiled OK.
Maven, instead, won't include a runtime dependency in the compilation phase, so a compile error is raised.
In brief: You should include guava-15.0 (as well as any other artifact your code needs) as a direct dependency (with compile scope) in your pom file.

How to make JUnit4 + Hamcrest 1.3 + Mockito work from Eclipse AND Tycho

I've managed to get JUnit 4.12 + Hamcrest 1.3 + Mockito 2.8.47 to work in Eclipse so that when I add them as dependencies, my tests will run.
(The way I've done this is using the p2-maven-plugin to bundle the following
artifacts from Maven Central into plugins/a feature and provide them via P2:
junit 4.12
org.mockito.mockito-core 2.8.47
org.hamcrest.all 1.3.0
Adding the plugins to my test fragment as dependencies makes the tests
run in Eclipse.
However, the Tycho build of the same fragment will fail with the
following messages:
java.lang.LinkageError: loader constraint violation: loader (instance of org/eclipse/osgi/internal/loader/EquinoxClassLoader) previously initiated loading for a different type with name "org/hamcrest/Matcher"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.defineClass(ModuleClassLoader.java:273)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.defineClass(ClasspathManager.java:632)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findClassImpl(ClasspathManager.java:586)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClassImpl(ClasspathManager.java:538)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:525)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:325)
at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:345)
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:423)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
So it seems that some other plugin is loading the package
org.hamcrest.Matcher before my fragment does. This is probably due
to the import/export/partial import/partial export chaos surrounding the
JUnit/Hamcrest/Mockito setup.
Does anyone have an idea -- or even better: a working example -- of how to
get the three components work together both within the IDE (for quick
checks on whether tests run) and Tycho (for checks during the build)?
Seems like that the loader want the dependencies in a bundle.
But I guess you haven't put your test lib in a bundle.
You could try to add them in the dependencies of your product to see how it reacts.
Background
The root of the problem is, that org.junit already has a dependency to org.hamcrest.core. So when your test-plugins has a dependency to org.hamcrest.all (which contains everything of hamcrest-core and all other hamcrest artifacts), all classes specified in hamcrest-core exist twice. Once in the bundle of hamcrest-core and once in hamcrest-all, which is why you get the linkage error.
If you open the Manifest of org.junit in the Manifest-Editor of Eclipse and go to the 'Dependencies' tab it should show you org.hamcreast.core in the "Required Plug-ins" section and org.hamcreast.core should be re-exported. Or in the raw-manifest it should look like this:
Require-Bundle: org.hamcrest.core;bundle-version="1.3.0";visibility:=reexport
Solution 1 - add hamcrest sub-modules
Instead of adding the all hamcrest-modul containing hamcrest.all as dependency to my Eclipse test-bundle/project (via 'Require-Bundle'), I add the hamcrest sub-modules that I require, except for hamcrest-core (because it is already re-exported in my case). For me hamcrest-library was sufficient.
The available hamcrest sub-modules are (according to the org.hamcrest:hamcrest-parent pom, which can be found here: https://repo1.maven.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom):
hamcrest-core
hamcrest-library
hamcrest-generator
hamcrest-integration
Creating the p2-Repo containing the required bundles
When using Maven and the 'org.reficio:p2-maven-plugin' to build the p2-repo that contains the mentioned test-bundles, the conversion of the maven-artifacts to OSGi-bundles does not produce fully working results by default.
Converting a maven-module to a full OSGi-bundle consists mainly of configuring the MANIFEST.MF to contain proper entries. For this the p2-maven-plugin utilizes "bnd tool".
By default the Java packages provided by all maven dependencies of a maven module are added as optional Imported-package when that module is converted into a OSGi-bundle.
In my case this had the consequence that the org.hamcrest.library bundle refereed to the packages from hamcrest-core only via Import-Package in its MANIFEST.MF.
But unfortunately with only this specified, the Equinox-ClassLoader did not find the classes from hamcrest-core in the test-runtime and threw a corresponding exception. Maybe this is also caused by the fact that hamcrest-core and hamcrest-library have a package "org.hamcrest" and bnd-tools adds the exported packages of a bundle to the imported packages again.
The solution in my case was to instruct the org.reficio:p2-maven-plugin respectively bnd-tools to add org.hamcrest.core as "Require-Bundle" to the Manifest of hamcrest-library. For this, the instructions-element shown below needs to be add to the artifact-element of org.hamcrest:hamcrest-library in the execution-configuration of the 'p2-maven-plugin' in the pom.xml used to build the p2-repo:
<artifact>
<id>org.hamcrest:hamcrest-library:1.3</id>
<instructions>
<Require-Bundle>org.hamcrest.core</Require-Bundle>
</instructions>
</artifact>
If hamcrest sub-modules other than hamcrest-library are are used, the instructions need to be analogous, corresponding to the dependencies listed in their pom.
Edit
Eclipse Orbit provides org.hamcrest.library, org.hamcrest.integrator and org.hamcrest.generator bundles that have have org.hamcrest.core as required bundle (if necessary):
https://download.eclipse.org/tools/orbit/downloads/
Appendix
In the end first solution caused a SecurityException:
java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package
Which is a known issue. The following two solutions avoid this issue and work properly during Tycho builds and from within Eclipse.
Solution 2 - bundle hamcrest sub-module jars with a plug-in
Another approach is to download the jar of the required hamcrest sub-module and bundle it with a Eclipse plugin directly, like it is described here:
https://www.vogella.com/tutorials/Hamcrest/article.html#hamcrest_eclipse
To bundle the jar with a plug-in, include it in the project and add it to the plug-ins classpath. Go to the Runtime-Tab of the Manifest-Editor and klick Add... in the Classpath section and select the jar. This should add the jar to the .classpath, MANIFEST.MF and build.properties file properly.
Make sure the jar is included before the other plug-in dependencies (which include hamcrest-core), as stated in the mentioned tutorial.
If hamcrest should be used in multiple test-projects/fragments, add the jar to a test plug-in all other test-projects depend on.
Solution 3 - use org.hamcrest 2.x
Since hamcrest-2 there is only one org.hamcrest jar/artifact that includes everything from hamcrest. Using hamcrest 2 avoids all the issues and is my preferred solution. Except for the changed packaing of hamcrest the API did not break, so it should be sufficient to just include org.hamcrest:
https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1
In order to create a p2-repo that includes org.hamcrest-2.2 the following sippet has to be included into the configuration-artifacts element of the p2-maven-plugin execution in the pom.xml:
<artifact>
<id>org.hamcrest:hamcrest-core:2.2</id>
<instructions>
<Require-Bundle>org.hamcrest;bundle-version="2.2.0";visibility:=reexport</Require-Bundle>
</instructions>
</artifact>
<artifact>
<id>org.hamcrest:hamcrest:2.2</id>
</artifact>
The IUs org.hamcrest.core 2.2 and org.hamcrest have to be included in the target-platform to make them available for plug-ins in Eclipse and during. All plug-ins which depend on org.junit now have org.hamcrest also available.
This aproach works because org.hamcrest.core still exists in version 2 stream, even tough it is deprected and empty. Its only purpose is to redirect build-systems to the new org.hamcrest-2.x jar/artifact. Therefore org.hamcrest.core-2.2 specifies a compile dependency to
org.hamcrest-2.2 in its pom.xml. Unfortunately the p2-maven-plugin dosn't translate it directly into a bundle-requirement for org.hamcrest in the manifest, but with the sippet above enforces that.
Because org.junit requires the bundle org.hamcrest.core with a minimal version of 1.3 (but without upper-bound) it uses the present org.hamcrest.core-2.2 . org.hamcrest.core-2.2 again requires org.hamcrest-2.2 and re-exports it. This makes org.junit use org.hamcrest-2.2 in the end and because org.junit re-exports hamcrest-core it also provides org.hamcrest-2.2 immediately to all depended plug-ins.
Note
If you want to play around with different variants of a jar, don't forget to clear (means delete on the drive) the bundle pools of Maven (in <your-home>/.m2/repository/p2/osgi/bundle/ and Eclipse PDE (in <your-workspace>/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/) in between. Otherwise you will always use the first one, because jar's with the same version are not updated.

How to find unused sbt dependencies?

My build.sbt has a lot of dependencies now. How do I know which dependencies are actually being used?
Maven seems to have dependency:analyse http://maven.apache.org/plugins/maven-dependency-plugin/
Is there something similar for sbt?
There is the sbt-explicit-dependencies plugin, which has been developed recently. It has direct commands in the SBT console to:
Enforce explicit direct declaration of dependencies, thus disallowing transitive dependencies.
Detect and remove unneeded dependencies.
you can use sbt-dependency-graph plugin. it shows dependencies in different graphical representations. also you can try to use tattletale, but it's not integrated with sbt. it'll require you to copy managed dependencies (retrieveManaged := true). this tool not only shows dependency graph, but analyzes class usage and can display unused dependencies (including transitive)