Skip to content

Commit

Permalink
Hide JDTCompilerAdapter from org.eclipse.jdt.core class loader
Browse files Browse the repository at this point in the history
See README.md why the JDTCompilerAdapter classloading is not trivial.

TL;DR: OSGI classloader from org.eclipse.jdt.core bundle should not find
JDTCompilerAdapter class (!) so the ant started from Eclipse can find it
inside jdtCompilerAdapter.jar contributed by ... org.eclipse.jdt.core
bundle.

Fixes eclipse-pde/eclipse.pde#419
  • Loading branch information
iloveeclipse committed Dec 6, 2022
1 parent 899f82e commit db6a1f8
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
8 changes: 8 additions & 0 deletions org.eclipse.jdt.core.compiler.batch/.settings/.api_filters
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jdt/core/JDTCompilerAdapter.java" type="org.eclipse.jdt.core.JDTCompilerAdapter">
<filter comment="See eclipse-pde/eclipse.pde#419 issue" id="305365105">
<message_arguments>
<message_argument value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<message_argument value="org.eclipse.jdt.core.compiler.batch_3.33.0"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java" type="org.eclipse.jdt.core.compiler.batch.BatchCompiler">
<filter id="1108344834">
<message_arguments>
Expand Down
5 changes: 2 additions & 3 deletions org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Bundle-Vendor: Eclipse.org
Automatic-Module-Name: org.eclipse.jdt.core.compiler.batch
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
Export-Package: org.eclipse.jdt.core,
Export-Package: META-INF.services,
org.eclipse.jdt.core.compiler,
org.eclipse.jdt.core.compiler.batch,
org.eclipse.jdt.internal.antadapter;x-friends:="org.eclipse.jdt.core",
Expand All @@ -29,5 +29,4 @@ Export-Package: org.eclipse.jdt.core,
org.eclipse.jdt.internal.compiler.parser.diagnose;x-friends:="org.eclipse.jdt.core",
org.eclipse.jdt.internal.compiler.problem;x-friends:="org.eclipse.jdt.core",
org.eclipse.jdt.internal.compiler.tool;x-friends:="org.eclipse.jdt.compiler.tool.tests,org.eclipse.jdt.core",
org.eclipse.jdt.internal.compiler.util;x-friends:="org.eclipse.jdt.core.internal.tools,org.eclipse.jdt.core",
META-INF.services
org.eclipse.jdt.internal.compiler.util;x-friends:="org.eclipse.jdt.core.internal.tools,org.eclipse.jdt.core"
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
## Notes for maintainers of the JDTCompilerAdapter (ant support) in ECJ.

The org.eclipse.jdt.core.JDTCompilerAdapter class can be used by PDE/ant
via jdtCompilerAdapter.jar if running ant tasks from inside Eclipse or by ant
directly (by adding org.eclipse.jdt.core.compiler.batch jar to ant classpath)
if running in a separated VM without OSGI.

### Standalone ant use

Using JDTCompilerAdapter class from standalone ant is straightforward - the
org.eclipse.jdt.core.compiler.batch jar should be added to the ant javac classpath
in some way, like for example here:

```
<javac destdir="${temp.folder}/@dot.bin" failonerror="${javacFailOnError}" verbose="${javacVerbose}"
debug="${javacDebugInfo}" includeAntRuntime="no" source="${javacSource}" target="${javacTarget}" encoding="UTF-8">
<compilerarg line="${compilerArg}" compiler="${build.compiler}"/>
<classpath refid="@dot.classpath" />
<src path="src/" />
<compilerarg line="-properties &apos;.settings/org.eclipse.jdt.core.prefs&apos;" compiler="org.eclipse.jdt.core.JDTCompilerAdapter" />
<compilerarg line="-log &apos;${temp.folder}/@dot.binnull&apos;" compiler="org.eclipse.jdt.core.JDTCompilerAdapter" />
<compilerarg line="-g -showversion -encoding UTF-8 -preserveAllLocals
-enableJavadoc -nowarn:[src-gen] -nowarn:[.src-gen] -time" compiler="org.eclipse.jdt.core.JDTCompilerAdapter" />
<compilerclasspath>
<pathelement path="${ecjBatchCompilerJarLocation}"/>
</compilerclasspath>
</javac>
```

### Eclipse (OSGI) embedded ant use

Using JDTCompilerAdapter class from ant started from OSGI container (Eclipse) is
not trivial and has few pitfalls.

First of all, org.eclipse.jdt.core.JDTCompilerAdapter class is packaged into a dedicated
jdtCompilerAdapter.jar that is **not** part of org.eclipse.jdt.core.compiler.batch bundle!

This jdtCompilerAdapter.jar is packaged **inside** org.eclipse.jdt.core bundle for some obscure reasons
and is extracted at runtime in org.eclipse.ant.internal.ui.datatransfer.BuildFileCreator.addInitEclipseCompiler().

Second most surprising point is: if the JDTCompilerAdapter code runs in OSGI environment, in order
to be properly loaded by ant which is started by PDE/ant.core bundle via
org.eclipse.ant.core.AntRunner.run(Object), the org.eclipse.jdt.core.JDTCompilerAdapter class
should **NOT** be found by classloaders of org.eclipse.jdt.core or org.eclipse.jdt.core.compiler.batch bundles!

The reason is, that the JDTCompilerAdapter class itself needs ant classes for class initialization,
but that must be **same** ant classes loaded by org.eclipse.ant.internal.core.AntClassLoader.
If the ant classes needed by JDTCompilerAdapter class are loaded by OSGI bundle loaders,
ant engine can't use them (even if they are coming from same jar)! From Java
runtime point of view they are different because loaded by a different classloader.

Therefore the code in org.eclipse.ant.internal.core.AntClassLoader.loadClassPlugins(String)
that goes over possible **bundle** classloaders that contribute ant tasks for Eclipse,
**must** fail to load org.eclipse.jdt.core.JDTCompilerAdapter class and return *null*!

This is surprising at least, and has some non trivial consequences.

The main one is: org.eclipse.jdt.core.JDTCompilerAdapter should be "not visible"
for default OSGI class loading from org.eclipse.jdt.core bundle that contributes
extra ant classpath entry jdtCompilerAdapter.jar,
and therefore org.eclipse.jdt.core package should be **not exported** in MANIFEST.MF
by org.eclipse.jdt.core.compiler.batch!

After failing to load JDTCompilerAdapter class in AntClassLoader.loadClassPlugins(String)
the AntClassLoader code goes to the parent classloader (which is URLClassLoader)
and the parent walks over **extra** ant classpath entries contributed by plugins
via "org.eclipse.ant.core.extraClasspathEntries" extension point (see
org.eclipse.ant.core.AntCorePreferences.computeDefaultExtraClasspathEntries(List)).

The URLClassLoader finally finds and loads JDTCompilerAdapter in jdtCompilerAdapter.jar
contributed by org.eclipse.jdt.core as an extra ant classpath entry
(with all the required ant classes found by ant own classloader)!
The URLClassLoader (AntClassLoader) should be initialized with core ant libraries at the beginning, so
it has no issues to satisfy all JDTCompilerAdapter ant dependencies.

0 comments on commit db6a1f8

Please sign in to comment.