How to add org.eclipse.swt (and other plugin dependencies) as an automatic Java9 module? - eclipse-plugin

In order to be able to use my Eclipse plugin "treezCore" also as a Java9 module I created a module-info.java in my src folder.
Furthermore, I moved the Plug-in Dependencies from the Classpath to the Modulepath. I can see a module "org.eclipse.swt.3.106.1.v20170926" in the plugin dependencies:
However, I am not able to reference that module in my module-info.java. I tried
require org.eclipse.swt.3.106.1.v20170926;
require org.eclipse.swt;
require swt;
None of those options worked. The jar file \plugins\org.eclipse.swt_3.106.1.v20170926-0519.jar that is used by Eclipse does not contain a module definition and
jar --file org.eclipse.swt_3.106.1.v20170926-0519.jar -d
says that the module descriptor can not be derived. Also see
Unable to derive module descriptor for auto generated module names in Java 9?
If I download a newer version of swt.jar from
http://download.eclipse.org/eclipse/downloads/drops4/R-4.7.1a-201710090410/download.php?dropFile=swt-4.7.1a-win32-win32-x86_64.zip
I get following output that looks promising:
swt automatic
requires java.base mandated
contains org.eclipse.swt
contains org.eclipse.swt.accessibility
contains org.eclipse.swt.awt
contains org.eclipse.swt.browser
contains org.eclipse.swt.custom
contains org.eclipse.swt.dnd
contains org.eclipse.swt.events
contains org.eclipse.swt.graphics
contains org.eclipse.swt.internal
contains org.eclipse.swt.internal.gdip
contains org.eclipse.swt.internal.image
contains org.eclipse.swt.internal.mozilla
contains org.eclipse.swt.internal.mozilla.init
contains org.eclipse.swt.internal.ole.win32
contains org.eclipse.swt.internal.opengl.win32
contains org.eclipse.swt.internal.webkit
contains org.eclipse.swt.internal.win32
contains org.eclipse.swt.layout
contains org.eclipse.swt.ole.win32
contains org.eclipse.swt.opengl
contains org.eclipse.swt.printing
contains org.eclipse.swt.program
contains org.eclipse.swt.widgets
I also depend on org.eclipse.jface and could not find a seperate download for it.
=> Do I really have to wait for a new release of Eclipse that uses new plugin versions including module definitions?
Or can I somehow reference the old version of swt from the plugins folder, even if it does not include a module definition? I looked for an easy way to define an alias or a fallback dependency e.g.
requires ../plugins/org.eclipse.swt_3.106.1.v20170926-0519.jar as 'org.eclipse.swt'
or
requires org.eclipse.swt fallback ../plugins/org.eclipse.swt_3.106.1.v20170926-0519.jar
but module-info.java does not seem to support such a syntax.
I have about 20 plugin dependencies and do not want to manually download each of them (if it would be possible) and include them as external jar file. Nor do I want to hack the individual Manifest/jar files in the Eclipse plugin folder. There are many jar files I would need to alter and an update of Eclipse would break that hack.
I am using Eclipse for RCP and RAP Developers, Version: Oxygen.1a Release (4.7.1a), Build id: 20171005-1200
Edit
When using Version: Photon Milestone 4 (4.8.0M4) Build id: 20171214-1849, the error in module-info.java vanishes when using
require org.eclipse.swt;
and having the Plug-in Dependencies in the Modulepath.
However, my imports do not work yet, see following image. If I move the Plug-in Dependencies from the Modulepath to the Classpath, the imports work but the error in module-info.java reappears.
I created a min example at
https://github.com/stefaneidelloth/Java9EclipsePluginExample/tree/master/MyPlugin
and I filed a bug report at
https://bugs.eclipse.org/bugs/show_bug.cgi?id=529089
Related questions:
How to use 3rd party library in Java9 module?
Unable to derive module descriptor for auto generated module names in Java 9?
Force Eclipse (Helios) to use a newer version of SWT at application runtime
JFace libraries stand-alone download (not picked from Eclipse plug-ins)
New Keywords in Java 9

What you observe is tracked in bug 525660, which starts with the observation that all existing (OSGi) artifacts of Eclipse don't work as automatic modules, because Java 9 fails to derive a valid module name from jar filenames of the shape org.eclipse.swt_3.106.1.v20170926-0519.jar.
Since this was discovered too late to request improving the algorithm for automatic module name derivation, this can only be fixed by adding Automatic-Module-Name headers to the manifests of future releases.
This header is present starting from Photon M4 as can be seen in org.eclipse.swt_3.107.0.v20171205-0742.jar, containing:
Automatic-Module-Name: org.eclipse.swt

Related

How to add a jar to the external library for a project w/o disappearing after sync and with imports working?

Presently having an annoying time getting a jar added to the external library for the project, then in turn not disappear when syncing and the imports working. Adding I figured out and answered in another question. The issue is to keep persistent and accessible to a jar I create within the project for import.
I am not sure if I am missing a step or forgot to set something. I am using a modified gradle (forgegradle) to create the project. Have not found a solution with the documentation, or any for IntelliJ yet. I am generally new with IntelliJ, choosing to use it instead eclipse which I have previously used.
The goal is a to create an add-on for a mod to another jar. The main jar already in the external library from the start, now attempting to add the mod to it. I could modify the mod, but it is not my code, so rather not simply modify it directly and repackage it.
a jar added to the external library for the project, then in turn not disappear when syncing and the imports working
If you are using an external build tool / system that syncs with IntelliJ it is recommended to use that build tool / system to add dependencies.
IntelliJ will always take a backseat, and treat the build tooling / system as the source of truth for the project model as best it can.
You mention you are using gradle, I would recommend adding the dependency as a managed dependency that is, let gradle download it from a repository, and resolve the dependency/library itself.
If you can not do this, and you can't host a repository yourself, The next best recommendation I have, is creating a 'libs' folder inside the project, that contains jars that can't be found in repositories (They may be mods or plugins that were never published)
You can read up on how to add a library folder to gradle here: How to add local .jar file dependency to build.gradle file?

Muting Java 9 split package errors on IntelliJ

I have a JDK 9 project. When running mvn install, everything works fine. When using IntelliJ 2017.2.6 with JDK 9.0.4 I come up
with dozens of compilation errors due to split packages. For example, in my POM I set a dependency on org.apache.solr:solr-core:7.2.1. One of the errors displayed by IntelliJ is:
Error:java: module solr.core reads package org.apache.lucene.search from both lucene.misc and lucene.sandbox
The rationale for the compilation error issued by IntelliJ is:
solr-core has Maven dependencies on artifacts lucene-misc and lucene-sandbox
Both lucene-misc.jar and lucene-sandbox.jar define classes in package org.apache.lucene.search
IntelliJ considers that lucene-misc.jar and lucene-sandbox.jar are JDK 9 modules (if fact, they are not modules, they have no module-info.java file). As two JDK 9 modules cannot participate to the same package, IntelliJ issues a compilation error.
By contrast, the Maven compiler pluging issues no error, because it considers lucene-misc.jar and lucene-sandbox.jar as belonging to
the class path, not to the module path.
I obviously don't want to re-package the Lucene stuff.
So my problem boils down to the following: how can I mute IntelliJ errors Error:java: module Mod1 reads package P from both Mod2 and Mod3?
[Short]
It's impossible if you want to run your application from a module code. You have to migrate your code which depend on collision JARs to non-module code and add your collitions jar on the class path. (as suggested in comments)
[Long]
Behind the scene the Intellij try to run the JVM, so the Intellij can run your application only if the JVM can do that.
When you run an application from module jar, that means that you run your application from named module. The module must require all of its dependencies which should be name modules. Note that even automatic modules which are created from your non-module JARs are indeed named.
Java 9 does not allow split-packages for the reason of the reliable configuration, only unnamed modules are excepted from this rule.
The only way to make it works it move your collision jars to unnamed module, but named module cannot depend on unnamed module
A named module cannot, in fact, even declare a dependence upon the unnamed module. This restriction is intentional, since allowing named modules to depend upon the arbitrary content of the class path would make reliable configuration impossible.
so if you don't want repackage collision jars you have to move your modules which require collision jars to non-module jar.
Your maven plugin done with it, because as #Nicolai said:
Maven places them on the class path (where split packages don't matter), whereas IntelliJ places them on the module path (leading to the problems you observe).
See also this answer about running the application from non-module code.

Configuring IntelliJ Platform plugin's workspace

I've been setting up the workspace for IntelliJ's plugin development. There is one issue that I'm not able to solve.
I have two plugins: A and B. The B plugin depends on A. The A plugin is provided as an install-ready zip package (I don't have the code and I don't want to add it to my project).
In the manual, I met this page. I added jars from the A plugin (extracted from the zip file) to the SDK that is use when running B plugin. Unfortunately, when the sandbox is being bootstrapped, I get the following error:
Problems found loading plugins:
Plugin "B" was not loaded: required plugin "A" not installed.
Disable B
Open plugin manager
Does it mean that plugins from the SDK are not installed automatically?
I tried to install the A plugin in the sandbox but then I got a casting exception - two different class loaders were used.
Of course, I have appropriate dependency configuration in the B.plugin.xml file:
<depends>A</depends>
My question is how should I provide the A plugin to be able to develop the B plugin? Is it possible to develop the B plugin without A's sources?
In the jars that I added to the SDK's classpath, there is a package that contains the plugin.xml file for the A plugin. This plugin is also not listed on the list of plugins.
I'm sure that both plugins are configured properly because there are no problems when I install both of them in a standalone IntelliJ instance. Additionally, I don't have any compilation errors.
After couple more hours of debugging. The A plugin is marked as not installed because in the PluginManagerCore:loadDescriptorsFromClassPath method there are no appropriate jars URLs provided. It seems that BootstrapClassLoaderUtil doesn't include all of the entries configured in the SDK.
I tried to set -Didea.additional.classpath property, but I got the class cast exception again.
Finally, I have found the solution.
The B plugin consists of other B submodules:
B.submodule-1
B.submodule-2
B.submodule-3
One of these submodules had dependencies to the A's submodule. Something like this:
B:
| B.plugin-submodule
| B.submodule-1
| A.submodule1
| A.submodule2
| B.submodule-2
| B.submodule-3
Based on the gradle setup, IntelliJ resolved all of the dependencies for all submodules. Initially, I removed Gradle dependencies and set the JDK only for the plugin submodule. It was required to do so for the others (submodule-1/2/3).

Embedding JARs into the OSGi bundle with maven-bundle-plugin

I’m trying to embed some JARs into single OSGi bundle using the feature of maven-bundle-plugin
The thing that worries me is that all packages of embedded JARs are put into the Import-Package header of the generated MANIFEST.MF.
If I specify explicitly to use only the packages I need, like in the following snippet:
Import-Package: org.osgi.framework
The build fails with BND error (unresolved references).
So, the question here is how can I build the bundle with embedded JARs with "Import-Package" header I need?
All the packages that are imported in your classes will be imported by bnd. Perhaps you do not want those packages imported because you know that at runtime you won't be needing them. If you cannot stop bnd from importing them, you can make them optional so that your bundle will still resolve even if they are not supplied by another bundle (at wire time). Try to add this:
<Import-Package>*;resolution:=optional<Import-Package>
To your maven bnd configuration in maven.
One possible reason why you are seeing "unexpected" packages in Import-Package header is the following:
A general good practice that supports collaboration model in OSGi is to import all packages that you export -- see this blog post by Peter Kriens for detailed explanation why. Bnd (and hence also maven-bundle-plugin) follows this practice by default and automatically imports all exported packages. Therefore you should first check your Export-Package header and make sure that you export only the packages you want.
Also if you want to export packages from the embedded dependencies then you should be careful to avoid duplication inside your bundle -- see section Embed-Dependency and Export-Package of the maven-bundle-plugin documentation.
You should use Bundle-ClassPath if you want to make classes available inside a bundle that contains JARs e.g.
Bundle-ClassPath: foo.jar,other.jar
Import-Package: org.osgi.framework,org.other.imported
You'll need to list the classes that foo.jar and other.jar import/use, but you won't need to list any of the packages in foo.jar or other.jar unless you're actually exporting them.
You can remove some packages from import-package scope when you embed a JAR into your bundle:
<Import-Package>![package_name9]<Import-Package>
inside pom.xml or if you use external *.bnd files:
Import-Package: ![package_name]

How do I add my fragment to the list of required-plugins on an existing plugin

I currently have an existing plugin, which references a class from a required plugin. I have replaced this code with a reference to a class which is part of my fragment.
I am facing two issues.
If I import my fragment as a jar file, I am not able to see the changes I have made as the plugin running as an eclipse application results in a ClassNotFoundException
To overcome this, I link an additional source (of fragment) to the existing plugin project. However, the link uses an absolute path, and makes it unfit for deployment.
I want to be able to package the plugin with the code modification and be able to "depend" on my fragment code. Is there a way I can add my fragment as a dependency?
For example:
Plugin Project I am changing : org.eclipse.*.editor
it depends on org.eclipse.*.edit
I have a fragment mydomain.*.edit which has org.eclipse.*.edit as host plugin
I want org.eclipse.*.editor to pick up mydomain.*.edit
instead of org.eclipse.*.edit
ps: I have also tried packaging the jar file for the mydomain.*.edit in the plugins directory and try and pick it up from there, it doesnt show up on the list when I click add required plugins on the dependency tab on the plugin.xml file of the org.eclipse.*.editor
Please let me know if I am not clear enough, I will try and rephrase it.
Thanks in advance!
If I understand correctly what you want to do, I don't think that it's possible. You will have to try some other way.
Plugins have dependencies on other plugins. Fragments don't exist as separate runtime entities, but only as extensions of a plugin. So your plugin can only refer to the 'editor' plugin.
Classes provided by a fragment can't (and shouldn't) be accessed directly. They can be returned by the original plugin (A) if they are implementing an executable extension provided by plugin A.
If you refer to the fragment's code from another plugin (B), the classes will be loaded by plugin B's classloader and be different from the ones that are loaded by plugin A.
What is the purpose of your fragment? Do you want to get access to internal code in plugin A? Do you want to extend an eclipse editor?
If you want to extend functionality that the original plugin is not exposing as extensible, I think the only way is to write a plugin, extend the editor class from the original plugin, register it alongside the original one and use it instead.
[Edit] Maybe this link will explain better: Eclipse FAQ
Hope this helps,
Vlad
Thanks Vlad,
Your explanation was very helpful. Unlike the extension based architecture that is truly intended for fragments, I had to modify a certain component in the editor that was not exposed as part of the extension. This modification referred to an external project I created as an fragment but could have been a normal java project packaged a jar file that I could place in the classpath of the editor.
I was able to resolve the dependency issues by placing the jar file in class path, however when I export the plugins and related plugins as jar files and place it in the dropin directory, it does not install correctly. (Nor does placing the jar files in the plugins directory)
The eclipse editor that I am trying to modify uses the EMF project. I have kept the EMF project in the workspace inorder to resolve dependencies of the editor. However when I replace the EMF jar files bundled with eclipse with the one in the workspace, the files that I want to edit are not correctly recognized.
Is there another way of doing this?