Bug 484629 - Injector searches for Nullable class which need not be available
Summary: Injector searches for Nullable class which need not be available
Status: CLOSED FIXED
Alias: None
Product: EPP
Classification: Technology
Component: Automated Error Reporting Client (AERI) (show other bugs)
Version: 4.6.0   Edit
Hardware: All All
: P3 blocker (vote)
Target Milestone: later   Edit
Assignee: EPP Error Reports CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 484891 (view as bug list)
Depends on:
Blocks:
 
Reported: 2015-12-18 02:32 EST by Andreas Sewe CLA
Modified: 2016-02-02 10:00 EST (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas Sewe CLA 2015-12-18 02:32:39 EST
This has been reported on epp-dev [1]. It is a consequence of Bug 472897, i.e., the use of @Nullable annotations.

[1] <http://dev.eclipse.org/mhonarc/lists/epp-dev/msg03813.html>
Comment 1 Andreas Sewe CLA 2015-12-18 02:35:22 EST
FYI, here's the actual exception:


org.eclipse.e4.core.di.InjectionException: java.lang.NoClassDefFoundError: org/eclipse/jdt/annotation/Nullable
at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(InjectorImpl.java:386)
at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorImpl.java:294)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(ContextInjectionFactory.java:162)
at org.eclipse.epp.internal.logging.aeri.ide.Startup$1.run(Startup.java:40)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
Caused by: java.lang.NoClassDefFoundError: org/eclipse/jdt/annotation/Nullable
at org.eclipse.epp.internal.logging.aeri.ui.model.impl.ModelPackageImpl.initializePackageContents(ModelPackageImpl.java:2002)
at org.eclipse.epp.internal.logging.aeri.ui.model.impl.ModelPackageImpl.init(ModelPackageImpl.java:326)
at org.eclipse.epp.internal.logging.aeri.ui.model.IModelPackage.<clinit>(IModelPackage.java:65)
at org.eclipse.epp.internal.logging.aeri.ui.utils.Constants.<clinit>(Constants.java:53)
at org.eclipse.epp.internal.logging.aeri.ui.functions.RegistryServersCreationFunction.compute(RegistryServersCreationFunction.java:49)
at org.eclipse.e4.core.internal.contexts.ValueComputation.get(ValueComputation.java:62)
at org.eclipse.e4.core.internal.contexts.EclipseContext.internalGet(EclipseContext.java:247)
at org.eclipse.e4.core.internal.contexts.EclipseContext.get(EclipseContext.java:213)
at org.eclipse.e4.core.internal.contexts.ContextObjectSupplier.fillArgs(ContextObjectSupplier.java:194)
at org.eclipse.e4.core.internal.contexts.ContextObjectSupplier.get(ContextObjectSupplier.java:178)
at org.eclipse.e4.core.internal.di.InjectorImpl.resolveArgs(InjectorImpl.java:505)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(InjectorImpl.java:368)
... 4 more
Caused by: java.lang.ClassNotFoundException: org.eclipse.jdt.annotation.Nullable cannot be found by org.eclipse.epp.logging.aeri.ui_1.100.0.v20151216-0616
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:444)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:357)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:349)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 16 more
Comment 2 Andreas Sewe CLA 2015-12-18 03:07:15 EST
Some more details:

The org.eclipse.epp.logging.aeri.ui bundle imports org.eclipse.jdt.annotations like this:

 Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[1.0.0,2.0.0)";resolution:=optional

But ModelPackageImpl.initializePackageContents contains this line

  initEDataType(nullableEDataType, Nullable.class, "Nullable", IS_SERIALIZABLE, !IS_GENERATED_INSTANCE_CLASS);

The explicit Nullable.class reference is the problem; the annotation need not be on the classpath due to resultion:=optional.

I am unfortunately not an ECore/EMF expert, so I don't know how to teach it to use the annotation in the generated code to annotate methods with but not as a class literal in methods like initializePackageContents.
Comment 3 Andreas Sewe CLA 2015-12-18 06:08:34 EST
(In reply to Andreas Sewe from comment #2)
> I am unfortunately not an ECore/EMF expert, so I don't know how to teach it
> to use the annotation in the generated code to annotate methods with but not
> as a class literal in methods like initializePackageContents.

FYI, asked on the ECore forum how to tweak code generation for compilet-time annotations [1].

[1] <https://www.eclipse.org/forums/index.php/m/1717972/#msg_1717972>
Comment 4 Eclipse Genie CLA 2015-12-18 07:24:10 EST
New Gerrit change created: https://git.eclipse.org/r/63010
Comment 5 Andreas Sewe CLA 2015-12-18 07:38:18 EST
(In reply to Eclipse Genie from comment #4)
> New Gerrit change created: https://git.eclipse.org/r/63010

This implements just a *workaround*. The org.eclipse.jdt.annotations bundle should really be a compile-time dependency, but the ECore generated code currently forces it to be a runtime dependency. However, until someone with more ECore knowledge has time to look at it, it may serve.
Comment 6 Eclipse Genie CLA 2015-12-18 08:50:49 EST
New Gerrit change created: https://git.eclipse.org/r/63020
Comment 7 Marc-André Laperle CLA 2015-12-18 09:58:02 EST
In Trace Compass, we depend on null annotations only at compile by only adding them to build.properties, not manifest.mf. For example:
http://git.eclipse.org/c/tracecompass/org.eclipse.tracecompass.git/tree/common/org.eclipse.tracecompass.common.core/build.properties
Comment 8 Andreas Sewe CLA 2015-12-18 10:08:21 EST
(In reply to Marc-Andre Laperle from comment #7)
> In Trace Compass, we depend on null annotations only at compile by only
> adding them to build.properties, not manifest.mf. For example:
> http://git.eclipse.org/c/tracecompass/org.eclipse.tracecompass.git/tree/
> common/org.eclipse.tracecompass.common.core/build.properties

Thanks for the pointer. That is certainly an option *if* we can get ECore to not generate code not referencing the Nullable.class literal. Any idea how to do that?
Comment 9 Marc-André Laperle CLA 2015-12-18 10:14:28 EST
(In reply to Andreas Sewe from comment #8)
> (In reply to Marc-Andre Laperle from comment #7)
> > In Trace Compass, we depend on null annotations only at compile by only
> > adding them to build.properties, not manifest.mf. For example:
> > http://git.eclipse.org/c/tracecompass/org.eclipse.tracecompass.git/tree/
> > common/org.eclipse.tracecompass.common.core/build.properties
> 
> Any idea how to do that?

Oh! No, sounds more complicated! I have no experience in ECore generated code (or even anything advanced using annotations). But...maybe you can do Nullable.class.getAnnotations(), check if has @Retention(RetentionPolicy.CLASS) ?
Probably good to check that for any classes actually!
Comment 10 Andreas Sewe CLA 2015-12-18 10:28:16 EST
(In reply to Marc-Andre Laperle from comment #9)
> Oh! No, sounds more complicated! I have no experience in ECore generated
> code (or even anything advanced using annotations). But...maybe you can do
> Nullable.class.getAnnotations(), check if has
> @Retention(RetentionPolicy.CLASS) ?
> Probably good to check that for any classes actually!

Maybe I misunderstand you, but the Nullable.class.getAnnotations() call introduces (due to the class literal) a runtime dependency to the @Nullable annotation, even though it has RetentionPolicy.CLASS.
Comment 11 Marc-André Laperle CLA 2015-12-18 10:38:08 EST
(In reply to Andreas Sewe from comment #10)
> (In reply to Marc-Andre Laperle from comment #9)
> > Oh! No, sounds more complicated! I have no experience in ECore generated
> > code (or even anything advanced using annotations). But...maybe you can do
> > Nullable.class.getAnnotations(), check if has
> > @Retention(RetentionPolicy.CLASS) ?
> > Probably good to check that for any classes actually!
> 
> Maybe I misunderstand you, but the Nullable.class.getAnnotations() call
> introduces (due to the class literal) a runtime dependency to the @Nullable
> annotation, even though it has RetentionPolicy.CLASS.

Or maybe I misunderstood you :) I'm talking about the generator code, not the generated code. I have no idea how this is done. In my head, it went like this:

class ECoreCodeGenetator {

void generateCode(Class clazz) {
// magic!
clazz.getAnnotations() ...
// magic that decides not to generate initEDataType(Nullable.class)
}

But I have no knowledge about ECore and AERI, so I'll be quiet now :)
Comment 13 Jonah Graham CLA 2015-12-25 07:55:08 EST
*** Bug 484891 has been marked as a duplicate of this bug. ***