[
https://issues.apache.org/jira/browse/LUCENE-7870?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16055874#comment-16055874
]
Uwe Schindler edited comment on LUCENE-7870 at 6/20/17 2:49 PM:
----------------------------------------------------------------
Hi Andreas,
this issue should be solved in Lucene 7.0. We will not backport this as it
breaks backwards compatibility: We no longer use the context class loader for
looking up services. It takes the class loader that defined the interface. If
you require another one (e.g. in OSGI without using buddy classloading) you can
call Codec.reloadCodecs(ClassLoader) and similar methods. See the MIGRATE.txt
in Lucene 7.
was (Author: thetaphi):
Hi Andreas,
this issue should be solved in Lucene 7.0. We will not backport this as it
breaks backwards compatibility: We no longer use the context class loader for
looking up services. It takes the class loader that defined the interface. If
you require another one (e.g. in OSGI without using buddy classloading) you can
call Codec.reloadCodes(ClassLoader) and similar methods. See the MIGRATE.txt in
Lucene 7.
> Use cl.loadClass(...) instead of Class.forName(..., cl) in SPIClassIterator
> ---------------------------------------------------------------------------
>
> Key: LUCENE-7870
> URL: https://issues.apache.org/jira/browse/LUCENE-7870
> Project: Lucene - Core
> Issue Type: Bug
> Affects Versions: 5.2.1, 6.1
> Environment: Eclipse Equinox 4.7
> Reporter: Andreas Sewe
>
> This issue is initially described in [Eclipse Bug
> 517935|https://bugs.eclipse.org/bugs/show_bug.cgi?id=517935] and prevents
> multiple versions of Lucene Core coexisting in an Equinox environment (FYI,
> Equinox is the OSGi container used by the Eclipse IDE).
> Here’s how the problem manifests: While Equinox cleanly separates two
> versions of the same Lucene Core bundle (e.g.,
> {{org.apache.lucene.core_5.2.1}} and {{org.apache.lucene.core_6.1.0}}) using
> two different bundle class loaders, it uses a single context classloader for
> all threads: the
> [{{ContextFinder}}|https://wiki.eclipse.org/Context_Class_Loader_Enhancements#Context_Finder_2].
> When asked to load a class, the {{ContextFinder}} *initiates* a search
> through all bundle class loaders currently “on“ the call stack; the class to
> be loaded is then *defined* by the respective bundle’s class loader.
> And here is where the use of {{Class.forName(..., classLoader)}} rather than
> {{classLoader.loadClass(...)}} causes problems. Consider the following
> sequence of events:
> # The {{NamedSPILoader}} of bundle {{o.a.l.core_5.2.1}} (re)loads some
> service (e.g., the {{Lucene50PostingFormat}}).
> ## It (through {{SPIClassIterator}}) first uses {{Class.forName}} with the
> bundle class loader of {{o.a.l.core_5.2.1}} (as per LUCENE-4713) to
> successfully load {{Lucene50PostingFormat}} from the {{o.a.l.core_5.2.1}}
> bundle.
> ## Then (through another {{SPIClassIterator}}) it uses {{Class.forName}} with
> the thread’s context class loader (here: {{ContextFinder}}) to load
> {{Lucene50PostingFormat}}. The {{ContextFinder}} delegates loading to the
> {{o.a.l.core_5.2.1}} bundle’s class loader, as that bundle is topmost on the
> call stack. This bundle class loader (again) successfully loads
> {{Lucene50PostingFormat}} from the {{o.a.l.core_5.2.1}} bundle.
> # Later, the {{NamedSPILoader}} of *another* bundle {{o.a.l.core_6.1.0}}
> loads the {{Lucene50PostingFormat}} service.
> ## It (through {{SPIClassIterator}}) first uses {{Class.forName}} with the
> bundle class loader of {{o.a.l.core_6.1.0}} to successfully load
> {{Lucene50PostingFormat}} from the {{o.a.l.core_6.1.0}} bundle.
> ## Then (through another {{SPIClassIterator}}) it uses {{Class.forName}} with
> the thread’s context class loader (the same {{ContextFinder}} again) to load
> {{Lucene50PostingFormat}}. As {{Class.forName}} remembers that the
> {{ContextFinder}} has successfully initiated the loading of
> {{Lucene50PostingFormat}} before, it simply returns the {{Class}} instance
> defined earlier in step _1.2_. But that class was defined by a different
> bundle class loader, namely that of {{o.a.l.core_5.2.1}}! This cache look up
> happens in native code; the {{ContextFinder}}‘s {{loadClass}} method isn’t
> even called, so there’s no way it can load the class from the
> {{o.a.l.core_6.1.0}} bundle, even though it now is topmost on the stack.
> ## Casting the {{Lucene50PostingFormat}} loading from bundle
> {{o.a.l.core_5.2.1}} to {{PostingFormat}} from bundle {{o.a.l.core_6.1.0}}
> then fails, leaving the {{o.a.l.core_6.1.0}} bundle in a broken state.
> It {{SPIClassIterator.next()}} would use {{classLoader.loadClass(...)}}
> rather than {{Class.forName(..., classLoader}}), then class loading in step
> _1.2_ wouldn’t *lock in* the {{Lucene50PostingFormat}} class from
> {{org.apache.lucene.core_5.2.1}}; instead, step _2.2_ would perform a
> completely independent look up that retrieves the class from the correct
> bundle. The cast in step _2.3_ would then succeed.
> At Eclipse Orbit, we plan to distribute a [patched
> version|https://git.eclipse.org/r/98804/] of Lucene Core, but obviously we
> would like to see the (one-line) change included in the upstream project.
> BTW, if you fear that bypassing {{Class.forName}} “caching” affects
> performance, then there’s no need to worry: Most {{ClassLoader}}
> implementations cache as well ({{findLoadedClass}}); it’s only
> {{ContextFinder}} that [overrides {{loadClass}}
> wholesale|https://git.eclipse.org/c/equinox/rt.equinox.framework.git/tree/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/ContextFinder.java?h=R4_7_maintenance],
> as it dynamically (based on the current call stack) delegates to the
> (caching) bundle class loaders.
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]