Tycho cannot resolve Require-Bundle: org.sample.ide.common;bundle-version="1.0.0.qualifier" - eclipse

I build an Eclipse plug-in project with Tycho.
I got this error message.
[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed: org.sample.ide.core 1.0.0.qualifier
[ERROR] Missing requirement: org.sample.ide.core 1.0.0.qualifier requires 'bundle org.sample.ide.common 1.0.0' but it could not be found
org.sample.ide.core-1.0.0.qualifier has org.sample.ide.common-1.0.0.qualifier as required bundle.
When I export the plug-in project with the Eclipse PDE export function, the dependent projects are recognized inside the same workspace.
And my manifest.mf has version like 1.0.0.qualifier, and my pom.xml has 1.0.0-SNAPSHOT. Is that problem?

Having artifacts with .qualifier versions is supported, so this is not the cause of your problem.
However I am not sure to what extend Tycho also supports .qualifier replacement in dependencies, e.g. Require-Bundle headers. (At least, this is buggy.) So you should try to build your project with a dependency to version 1.0.0 instead of 1.0.0.qualifier.

Tycho replaces the .qualifier with a timestamp or fixed string in the reactor build within all manifest files. It resolves the files from the repositories defined from the target files attached, and from the local repository. If none of these contain an exactly matching dependency, tycho will not succeed with the build.
Note that the resolution of PDE export is based on the current target set in Eclipse, and that PDE will replace the qualifier for all bundles open in the workspace. Tycho does not know of these, its scope is what is included in the reactor during the build.

Related

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.

Maven building a project using both Maven Dependencies and Referenced Libraries

Is there a command that will let Maven use the Referenced Libraries when building a project?
See the Dependencies section of Maven / POM Reference:
The cornerstone of the POM is its dependency list. Most every project depends upon others to build and run correctly, and if all Maven does for you is manage this list for you, you have gained a lot. Maven downloads and links the dependencies for you on compilation and other goals that require them. As an added bonus, Maven brings in the dependencies of those dependencies (transitive dependencies), allowing your list to focus solely on the dependencies your project requires.

Tycho Maven: Adding a local repository

I have a plug-in project with several dependencies. Among them, there are a couple that are NOT in the official p2 Eclipse repository. They have been installed manually from its "private" update site.
Tycho can not compile the plug-in since it cannot find out where the local dependency is.
[ERROR] Missing requirement: es.uma.lcc.e-motions 2.0.1.qualifier requires 'bundle es.upv.dsic.issi.moment.mdt.maudedaemon 1.3.6' but it could not be found
These dependencies are jars in the eclipse/plugins folder. Can I add this folder as repository to my generated pom.xml?

Am I misunderstanding the usage of Export-Package in OSGI Bundles?

I'm developing a plug-in that needs access to the class org.eclipse.swt.widgets.Display. This class is contained in org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar. However, the class is also exported by the manifest in com.ibm.rcp.jfaceex_6.2.2.20100729-1241 as follows:
Export-Package: com.ibm.rcp.jface.action,com.ibm.rcp.jface.launcher,co
m.ibm.rcp.jface.themes,com.ibm.rcp.jface.util,com.ibm.rcp.jface.viewe
rs,com.ibm.rcp.jface.window,com.ibm.rcp.jface.window.effects,com.ibm.
rcp.ui.widgets.api.jface,com.ibm.rcp.ui.widgets.api.swt
Require-Bundle: com.ibm.rcp.swtex,org.eclipse.swt,org.eclipse.core.run
time,org.eclipse.jface,org.eclipse.ui
Now, com.ibm.rcp.jfaceex is not included as part of my JRE System Library. It is, however, a bundle that includes classes of its own, as well as the exported packages above.
I was led to beleve that all I needed to do in my own project was to include a reference to it in my own project's build path, but this does not appear to work. The compiler is unable to resolve import statements against the classes in the org.eclipse.swt.widgets package.
If I need those classes, what, exactly do I need to do to import them correctly, and with the least amount of work?
Note We are not using Maven or any third party build tools. This is mandated by management, and I cannot change it.
UPDATE
Per the suggestion of E-Riz, below, I added org.eclipse.swt to the Required Bundles section of the Dependencies tab of my plug-in. Then, I attempt to export the project as follows:
Right click project, select Export.
Select Plug-in Development -> Deployable plug-ins and fragments
Select All, then click Finish
Eclipse builds the project, then tells me there were errors. Examination of the log reveals the following error:
1. ERROR in E:\NotesDev\Plug-in\com.ibm.lotuslabs.ui\src\com\ibm\lotuslabs\ui\UI.java (at line 1)
/**
^
The type org.eclipse.swt.widgets.Shell cannot be resolved. It is indirectly referenced from required .class files
There are dozens of these throughtout my code; one for every reference to a class or method in the org.eclipse.swt namespace bundle. This, despite the fact that the bundle debugs just fine!
UPDATE 2
I've discovered that you can, in fact, put absolute paths into the Bundle-Classpath in MANIFEST.MF. Oddly, this made the compile-time errors vanish. I am not convinced at this point that this is the correct thing to do, since absolute paths are certainly not guaranteed to correspond to the end-user's configuration.
However, installing the plug-in into Notes (the target platform), is not working as intended.
Notes reports that the plug-in installed successfully, but the plugin (an addition to the toolbar) does not appear. I am assuming, at this point, that something with the classpaths still isn't right.
UPDATE 3
Per request, the MANIFEST.MF and build.properties files. Please note that absolute paths were added by Eclipse, through the Dependencies and Runtime tabs.
MANIFEST.MF:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Context Plug-in
Bundle-SymbolicName: com.ibm.lotuslabs.context.service;singleton:=true
Bundle-Version: 1.0.2
Bundle-Vendor: IBM
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-Activator: com.ibm.lotuslabs.context.service.internal.ContextPlugin
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: context.jar,
lib/activation-1.1.1.jar,
lib/mail.jar,
lib/SatuitCRM_XML_API2.jar,
lib/commons-lang3-3.1/commons-lang3-3.1.jar,
E:/NotesDev/Notes/framework/rcp/eclipse/plugins/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ui,
org.eclipse.ui.views,
org.eclipse.swt,
com.ibm.rcp.swtex,
com.ibm.rcp.jfaceex,
com.satuit.core
Export-Package: com.ibm.lotuslabs.context.service.document,
com.ibm.lotuslabs.context.service.internal
Import-Package: org.eclipse.core.resources
build.properties:
output.. = bin/
bin.includes = META-INF/,\
context.jar,\
lib/activation-1.1.1.jar,\
lib/mail.jar,\
lib/commons-lang3-3.1.jar,\
lib/SatuitCRM_XML_API2.jar,\
plugin.xml,\
E:/NotesDev/Notes/framework/rcp/eclipse/plugins/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar
jars.compile.order = context.jar
source.context.jar = src/
Just because a bundle names a package in its Export-Package declaration does not necessarily mean that it contains the code for that package. A bundle can export packages from bundles that it depends on (although I think that's generally a bad idea in most cases).
For you, the solution is simple: in your MANIFEST.MF go to the Dependendencies tab and add org.eclipse.swt to the list of Required Plug-ins
Not quite sure, but two things come to mind.
Either remove the jar from your project classpath and add the com.ibm.rcp.jfaceex jar to your target platform (Preferences->PDE->Target platform and point to a directory containing the com.ibm.rcp.jfaceex jar)
Or leave the reference and also add the jar to your bundle classpath (on the runtime tab of the MANIFEST)
It don't quite see how this would result in this error, but classpath problems can manifest themselves in weird ways in PDE.
I have taken a look at the swt related bundles in eclipse juno:
org.eclipse.swt_3.100.0.v4233d.jar
org.eclipse.swt.win32.win32.x86_3.100.0.v4233d.jar
The widgets are in the second bundle which is a fragment to the first.
So you have to make sure both bundles are in the target platform. I am not sure if require bundle works in that case (it may work). You may try to instead import all packages you need.
Especially you need Import-Package on the package org.eclipse.swt.widgets.