The package com.faizan.org is accessible from more than one module: ProjectA, ProjectB using JDK 9+ during build in Eclipse 2019-12 - classpath

I have 2 projects, say ProjectA and ProjectB, both containing package com.faizan.org. ProjectA is added in the modulepath of ProjectB.
<classpathentry combineaccessrules="false" kind="src" path="/ProjectA">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
Now I am writing a new class in ProjectB that needs to import a class from com.faizan.org of ProjectA, but I get an error The package com.faizan.org is accessible from more than one module: ProjectA, ProjectB in eclipse 2019-12 using openJdk 12 and compiler compliance also set to 12.
How can I add external projects containing same package name to another project without classpath conflicts?
Also, in some cases unable to access methods of super class.

Simple answer: you cannot.
When you setup your Eclipse projects as Java modules, then the rules of the module system JPMS forbid that any module has access to the same package from two modules (each package must be "uniquely visible").
Next, you should revisit why you need to have the same package in both projects? If it is for whitebox testing, then please consider moving the tests to the same project, but in a separate source folder marked as containing tests. Then Eclipse will do all the necessary wiring behind the scenes, so that the tests are part of the module and not part of the module at the same time.
If it's not for the sake of whitebox testing, and you do want to adopt JPMS, then you are left with 2.5 options:
Move all code that shares a package into the same project / module.
Change the package structure to avoid the split package.
(Use a tricky set of JPMS options including --patch-module and likely more to let JPMS view the separate projects as one module -- while possible I would consider this as "successful migration")

Related

Eclipse RCP - Use Classes from a library that are imported from another plugin?

follow situation.
-pluiginCore <- includes many Libraries (libA,liB) via pom.xml, do nothing else
-pluginA..F <- want use classes from libA.
-pluginF..Z <- want use classes from libB.
Is this possible with RCP?
Is this a good way?
Do I need to import via pom.xml libA and LibB in each plugin where I wanna use it?
I added pluginCore as a dependency of pluginA but still cant use libA.
You have to do this using the directives in the MANIFEST.MF of the plugins.
For the plugin which contains the libraries you use the Bundle-ClassPath to specifies the jars in the plugin. For example:
Bundle-ClassPath: .,
lib/jogg-0.0.7.jar,
lib/jorbis-0.0.15.jar,
lib/vorbisspi1.0.2.jar
The . entry is for the normal code in the plugin, the other entries are jars in a lib directory.
You must also specify the additional jars in the build.properties for the plugin.
You use the Export-Package directive to say which packages from these jars are available to other plugins:
Export-Package: com.jcraft.jogg,
com.jcraft.jorbis
Plugins which wish to refer to these packages can either use Require-Bundle to add a dependency to the plugin exporting the packages, or they can use Import-Package to let Eclipse find the imported package.

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.

debug sbt sources too with eclipse

I'd like to navigate to the sbt sources when I debug my sbt build.
By using the sbt eclipse plugin I can debug e.g. my Build.scala file, which is great! And I can include the sbt plugin sources too by using:
> reload plugins
> eclipse withSources=true
But the sources to sbt itself aren't in the .classpath file generated by sbt-eclipse. I see that the source jars are in the ivy cache, but the sourcepath entry is missing:
<classpathentry kind="lib"
path="/home/lee/.ivy2/cache/org.scala-sbt/main-settings/jars/main-settings-0.13.1-RC2.jar"
/>
I'd like the generated class path to have a sourcepath like the following. (This was edited manually, I'd like to have it generated by sbt-eclipse):
<classpathentry kind="lib"
path="/home/lee/.ivy2/cache/org.scala-sbt/main-settings/jars/main-settings-0.13.1-RC2.jar"
sourcepath="/home/lee/.ivy2/cache/org.scala-sbt/main-settings/srcs/main-settings-0.13.1-RC2-sources.jar"
/>
(Tested with sbt 13.1-RC2 and sbt eclipse 2.4.0)
I see this sbt-dependency-manager plugin, but that looks awkward...
Is there an easier way to view sbt sources along with my sbt build?
I am, as originator of sbt-dependency-manager, must admit that there is not only problem to get sources. You may download sources by hands and manually attach them to your debugger, but Eclipse still unable to use them.
sbt-dependency-manager not only download, but also repackage jars. So in this way you should open 2 bugs :-):
about fetch sources in sbt-eclipse
about sources layout of SBT itself
I tried to avoid this issues and this is only solution that I know. Oh, you may switch to Idea or Ensime, of course - but this is not acceptable for me. Also I don't use sbt-eclipse at all because sbt-dependency-manager makes it useless.

How can I set in build.gradle the groovy nature of an Eclipse project?

After running gradle cleanEclipse Eclipse on the project it loses the Groovy nature. How can I set this nature automatically, or simply to say to the Gradle to leave it alone.
Edit:
According do doc, I can write in the build.gradle:
eclipse {
project {
natures 'some.extra.eclipse.nature', 'some.another.interesting.nature'
}
}
But what is the name of the groovy nature, or how could I get it?
I go to the .project and look:
<natures>
<nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>bndtools.core.bndnature</nature>
</natures>
org.eclipse.jdt.groovy.core.groovyNature - that is the nature name
And I am adding apply plugin: "groovy", as #Peter Niederwieser advised (thanks+1)
But
After running gradle cleanEclipse Eclipse I have correct .project file, and the project has "G" on the icon, but in the .classpath two lines are not present:
<classpathentry exported="true" kind="con" path="GROOVY_SUPPORT"/>
<classpathentry exported="true" kind="con" path="GROOVY_DSL_SUPPORT"/>
That ARE present, when I am setting the Groovy nature by hand.
And it seems, that these lines are important, for in that variant the project shows errors even on compile level - it doesn't see some Groovy methods.
Thinking about this again, Gradle will add a Groovy nature for those projects that have the groovy (or groovy-base) plugin applied. So either add that plugin on the Gradle side, or don't run cleanEclipse after you have added the Groovy nature manually, or switch to the Eclipse Gradle tooling instead of generating Eclipse files.
It seems, that for a real groovy nature setting, I need not only to set
natures.add 'org.eclipse.jdt.groovy.core.groovyNature'
and
apply plugin: "groovy"
, but also to edit the classpath.
eclipse {
classpath {
file {
withXml {
Node node = it.asNode()
node.appendNode('classpathentry',[exported:"true",kind:"con",path:"GROOVY_SUPPORT"])
node.appendNode('classpathentry',[exported:"true",kind:"con",path:"GROOVY_DSL_SUPPORT"])
}
}
}
}
What is interesting, if we turn on the groovy classpath by hand, only the path "GROOVY_SUPPORT" appears in the .classpath file. It is also enough for my project. But when turning by hand the whole Groovy nature, both paths appear. So, I am better including them both, too.
The Gradle-Eclipse plugin (that is gradle tooling for Eclipse, not the Eclipse plugin for gradle). Should be installable on Eclipse 3.6. (I say should be installable because we no longer test on 3.6, but there shouldn't be any reason why it is broken). If you install this plugin, you should be able to import your gradle project into Eclipse without calling gradle Eclipse.
You can install from the update site here:
http://dist.springsource.com/release/TOOLS/gradle
And more information on the project is here:
https://github.com/SpringSource/eclipse-integration-gradle

AspectJ - Compile-time vs load-time weaving

I am having trouble understanding aspectJ's compile-time and load-time weaving and figuring out what to use(and how to use ajc) to compile and build my project.
Here's my project structure:-
TestProject : a java service library.
This is being used by a few other
projects. This project do not contain
any aspects.
TestProject-Aspects : Contains just
aspects which advice a few classes in
TestProject. I am not using the
AspectJ5 annotation style and all my
joinpoints are just at the method
execution currently.
My questions:
ajc vs iajc and how are they
different?
Is there any need for weaving?
Will something like this work ?
Compile TestProject-Aspects
<iajc>
sourceroots=${sources.dir}
destdir=${classes.dir}
classpath=${standard.compile.classpath}
</iajc>
Compile TestProject
<iajc>
sourceroots=${sources.dir}
destdir=${classes.dir}
classpath=${standard.compile.classpath}
inpath=${[TestProject-Aspects]pkg.classpath}
</iajc>
Don't I have to use javac at all ?
which I was initially using to compile
TestProject?
ajc and iajc are extensions of the JDT compiler that comes with Eclipse. So, ajc and iajc will produce exactly the same byte code for pure Java as Eclipse would (which contains some minor differences to Oracle's javac).
ajc and iajc are basically the same except that iajc is incremental (that's the i in iajc). This means that the compiler checks time stamps and does a smarter incremental build if possible and avoids full builds (just like when using AJDT inside of eclipse). Other than this functionality, they are essentially the same. See here for more information:
http://www.eclipse.org/aspectj/doc/released/devguide/antTasks-iajc.html
If a project contains no aspects, using the ajc compiler is optional. These projects can be on the inpath of a project that contains aspects. To compile that contain code-style aspects, then you need to use ajc.
Annotation style aspects are a little different. If you are using annotation style for LTW only, then you can use javac to compile them as long as the correct aop.xml is created weaver is available at runtime.
However, annotation style with CTW weaving does require ajc.
In your particular case above, you can compile TestProject using javac as long as it is on the inpath of your aspect project. This would mean that the class files of your TestProject would be re-written and combined with the class files from your aspect project.
Or, if you are using LTW, then you don't need to add your TestProject to any inpath and you can use javac. But, you must set up your application for LTW at runtime.
EDIT
To answer your comment below:
Yes. You can compile your aspects project first using ajc or the iajc task. Then, you can compile your second, pure java project also by using the iajc task and additionally by putting the results of your first project on the aspect path. You cannot use javac for this at all.
The ant build.xml snippet will look something like this:
<project name="simple-example" default="compile" >
<taskdef
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
<classpath>
<pathelement location="${home.dir}/tools/aspectj/lib/aspectjtools.jar"/>
</classpath>
</taskdef>
<target name="compile" >
<iajc sourceroots="${home.dir}/TestProject-Aspects/src"
classpath="${home.dir}/tools/aspectj/lib/aspectjrt.jar"
destDir="${home.dir}/TestProject-Aspects/bin"/>
<iajc sourceroots="${home.dir}/TestProject/src"
classpath="${home.dir}/tools/aspectj/lib/aspectjrt.jar"
destDir="${home.dir}/TestProject/bin"
aspectPath="${home.dir}/TestProject-Aspects/bin"/>
</target>
</project>
See here for more details on iajc:
http://www.eclipse.org/aspectj/doc/released/devguide/antTasks-iajc.html