[ https://issues.apache.org/jira/browse/UIMA-5054?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15419558#comment-15419558 ]
Marshall Schor edited comment on UIMA-5054 at 8/13/16 7:05 PM: --------------------------------------------------------------- Even with a null class path, the creation of an extension class loader sets a "boundary" for JCas loading. Inside this boundary, JCas classes are loaded the first time (when the process method is called passing a JCas), and even though the classes get loaded by the parent classloader (because the extension class path loader's classpath is ""), the generators for these classes are associated (in a hashmap) with the classloader in effect (that is, the UIMA Extension loader). One possible "fix" for this is to have this process set the generator for the parent classloader(s) depending on what the "loading" classloader used was. This sounds like a bug fix we could do in UIMA (assuming it's possible to detect the "loading" class loader - not sure if class.getClassloader returns the "initiating" or "loading" loader... After more thought, this isn't the cause or the right fix. The cause is a bug in the design of when JCas classes are loaded. The design loads these lazily, on the first creation of JCas CAS from a CAS, and the load is done one time (bug). In this example, the first creation of JCas occurs while in the context of class loader #2; JCas class are loaded properly. However, when we exit that context and code loaded under class loader #1 is executed, it also switches from the CAS to the JCas (in CustomStatusCallbackListener's entityProcessComplete method). That switch to JCas is the first switch that happens while in the context where ClassLoader #1 is in charge. When this happens, the JCas classes loadable via that class loader ought to be loaded and set up in the generators - this doesn't happen because the logic for JCas initialization is buggily to only do it once. A consequence of this bug would be that had ClassLoader #1 had a definition for some UIMA type and ClassLoader #2 had a different definition, because of the order in which the swtich to JCas occurs, only the 2nd definition would be loaded. I'll put up another Jira for this. was (Author: schor): Even with a null class path, the creation of an extension class loader sets a "boundary" for JCas loading. Inside this boundary, JCas classes are loaded the first time (when the process method is called passing a JCas), and even though the classes get loaded by the parent classloader (because the extension class path loader's classpath is ""), the generators for these classes are associated (in a hashmap) with the classloader in effect (that is, the UIMA Extension loader). One possible "fix" for this is to have this process set the generator for the parent classloader(s) depending on what the "loading" classloader used was. This sounds like a bug fix we could do in UIMA (assuming it's possible to detect the "loading" class loader - not sure if class.getClassloader returns the "initiating" or "loading" loader... > JCas returning generic class instead of JCas cover class > -------------------------------------------------------- > > Key: UIMA-5054 > URL: https://issues.apache.org/jira/browse/UIMA-5054 > Project: UIMA > Issue Type: Bug > Components: Collection Processing > Affects Versions: 2.8.1SDK > Reporter: Richard Eckart de Castilho > Fix For: 2.9.0SDK > > > A DKPro Core user reported that when deploying an AE in a CPE > he was unable to access a JCas cover class in the > entityProcessComplete(...) CPE callback. See: > https://groups.google.com/d/msg/dkpro-core-user/-DtO5Ivnk9I/sjQAPPv1BwAJ > {noformat} > public void entityProcessComplete(CAS cas, EntityProcessStatus > status) { > try { > JCas jcas = cas.getJCas(); > // here getting a JCas cover class fails. Instead, > // an AnnotationImpl is returned from the jcas. > } catch (CASException e) { > e.printStackTrace(); > } > } > {noformat} > The problem appears to be that the static CAS classloaders are restored > *before* invoking the entityProcessComplete() callback (CPMEngine 3468): > {noformat} > try { > if (null != cas) > ((CASImpl)cas).switchClassLoaderLockCas(statCL); > statCL.entityProcessComplete(cas, eps); > } finally { > if (null != cas) > ((CASImpl)cas).restoreClassLoaderUnlockCas(); > } > {noformat} > Is there any reason that the classloaders are switched out before invoking > the callback? If not, any objection if I change the code such that the > callback is invoked before the classloaders are switched out? > {noformat} > Thread [[Procesing Pipeline#7 Thread]::] (Suspended (breakpoint at line 1021 > in CASImpl)) > CASImpl.setLocalFsGenerators(FSGenerator<FeatureStructure>[]) line: > 1021 > FSClassRegistry.swapInGeneratorsForClassLoader(ClassLoader, CASImpl) > line: 225 > JCasImpl.switchClassLoader(ClassLoader) line: 548 > CASImpl.switchClassLoader(ClassLoader) line: 4195 > CASImpl.switchClassLoaderLockCasCL(ClassLoader) line: 4183 > CASImpl.switchClassLoaderLockCas(Object) line: 4176 > CPMEngine.callEntityProcessCompleteWithCAS(StatusCallbackListener, CAS, > EntityProcessStatus) line: 3472 > ProcessingUnit.doNotifyListeners(Object, boolean, EntityProcessStatus) > line: 1650 > ProcessingUnit.notifyListeners(Object, boolean, EntityProcessStatus) > line: 1592 > ProcessingUnit.processNext(Object[], ProcessTrace) line: 917 > ProcessingUnit.run() line: 575 > {noformat} -- This message was sent by Atlassian JIRA (v6.3.4#6332)