[hibernate-issues] [Hibernate-JIRA] Issue Comment Edited: (HSEARCH-1115) Failure to load Analyzer class when deployed into AS7

Randall Hauch (JIRA) noreply at atlassian.com
Fri May 4 21:10:09 EDT 2012


    [ https://hibernate.onjira.com/browse/HSEARCH-1115?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=46541#comment-46541 ] 

Randall Hauch edited comment on HSEARCH-1115 at 5/4/12 8:08 PM:
----------------------------------------------------------------

Two uses of {{ReflectHelper.classForName(String)}} were changed to use the {{classForName(String,Class)}} form instead. In the latter method, if the class cannot be found on the thread's context class loader then the class will be loaded using the classloader of the class specified in the second parameter.

In one of the cases ({{DocumentBuilderHelper}}), the {{DocumentBuilderHelper}} class was passed as the second parameter, meaning that the same classloader used to load the Hibernate Search classes will be used.

In the second case ({{ConfigContext}}), the second parameter is the class of the {{SearchConfiguration}} implementation that was supplied to the {{ConfigContext}} constructor. This is better than using the {{ConfigContext}} class directly, since the {{SearchConfiguration}} implementation will be provided by the components using the {{SearchFactoryBuilder}} to build a {{SearchFactory}}. This means that the components' classloader will be used to load the {{Analyzer}} implementation class.

There are a few other uses of {{ReflectionHelper.classForName(String)}} in the Hibernate Search codebase, but I don't think they require the same classloading logic. (Needs verification.)

When used in a Java SE environment, there is no net difference in classloading behavior. However, in JBoss AS7 (or even OSGi) the different classloaders have a significant effect. Specifically, when used in JBoss AS7, the modules might look like this (where "{{-->}}" signifies 'depends on'):

{code:none}
org.foo (uses Hibernate Search, implements SearchConfiguration)
 --> org.hibernate.search.engine
     --> org.hibernate (specifically the hibernate-commons-annotations JAR)
     --> org.apache.lucene
     --> others
{code}

In this case, the result of the code before this change is that {{ConfigContext}} would expect to find the {{Analyzer}} implementation using the {{org.hibernate}} module (where the {{ReflectHelper}} class exists), which does cannot see any of the {{Analyzer}} implementations in {{org.apache.lucene}} nor any implementations provided by {{org.foo}}. After this change, {{ConfigContext}} uses {{org.foo}} class loader (since that's where the {{SearchConfiguration}} implementation class exists), and thus can see any {{Analyzer}} implementation provide in {{org.foo}}, {{org.hibernate.search.engine}}, {{org.apache.lucene}}, {{org.hibernate}} (if there were any), or any of the other modules.

All unit tests run by the build pass successfully with these changes.

      was (Author: rhauch):
    Two uses of ReflectHelper.classForName(String) were changed to use the classForName(String,Class) form instead. In the latter method, if the class cannot be found on the thread's context class loader then the class will be loaded using the classloader of the class specified in the second parameter.

In one of the cases (DocumentBuilderHelper), the DocumentBuilderHelper class was passed as the second parameter, meaning that the same classloader used to load the Hibernate Search classes will be used.

In the second case (ConfigContext), the second parameter is the class of the SearchConfiguration implementation that was supplied to the ConfigContext constructor. This is better than using the ConfigContext class directly, since the SearchConfiguration implementation will be provided by the components using the SearchFactoryBuilder to build a SearchFactory. This means that the components' classloader will be used to load the Analyzer implementation class.

There are a few other uses of ReflectionHelper.classForName(String) in the Hibernate Search codebase, but I don't think they require the same classloading logic.

When used in a Java SE environment, there is no net difference in classloading behavior. However, in JBoss AS7 (or even OSGi) the different classloaders have a significant effect. Specifically, when used in JBoss AS7, the modules might look like this (where "-->" signifies 'depends on'):

org.foo (uses Hibernate Search, implements SearchConfiguration)
 --> org.hibernate.search.engine
     --> org.hibernate (specifically the hibernate-commons-annotations JAR)
     --> org.apache.lucene
     --> others

In this case, the result of the code before this change is that ConfigContext would expect to find the Analyzer implementation using the org.hibernate module (where the ReflectHelper class exists), which does cannot see any of the Analyzer implementations in org.apache.lucene nor any implementations provided by org.foo. After this change, ConfigContext uses org.foo class loader (since that's where the SearchConfiguration implementation class exists), and thus can see any Analyzer implementation provide in org.foo, org.hibernate.search.engine, org.apache.lucene, org.hibernate (if there were any), or any of the other modules.

All unit tests run by the build pass successfully with these changes.
  
> Failure to load Analyzer class when deployed into AS7
> -----------------------------------------------------
>
>                 Key: HSEARCH-1115
>                 URL: https://hibernate.onjira.com/browse/HSEARCH-1115
>             Project: Hibernate Search
>          Issue Type: Bug
>            Reporter: Randall Hauch
>
> Specifying an analyzer class via the "hibernate.search.analyzer" configuration property results in an exception when initializing the Hibernate Search engine within the AS7 environment:
> {code}
> Caused by: org.hibernate.search.SearchException: Analyzer found with an unknown definition: org.apache.lucene.analysis.standard.StandardAnalyzer
>    at org.hibernate.search.impl.ConfigContext.initLazyAnalyzers(ConfigContext.java:252)
>    at org.hibernate.search.spi.SearchFactoryBuilder.initDocumentBuilders(SearchFactoryBuilder.java:434)
>    at org.hibernate.search.spi.SearchFactoryBuilder.buildNewSearchFactory(SearchFactoryBuilder.java:221)
>    at org.hibernate.search.spi.SearchFactoryBuilder.buildSearchFactory(SearchFactoryBuilder.java:145)
>    ...
> {code}
> Even setting the "hibernate.search.analyzer" property to "org.apache.lucene.analysis.standard.StandardAnalyzer" (which happens to be the default if no analyzer class is specified) will also fail.
> I believe this exception is occurring within the AS7 module class loading environment because during initialization of the Hibernate Search engine (e.g., {{SearchFactoryBuilder.buildSearchFactory}}), the {{ConfigContext.initAnalyzer}} method is called and uses Hibernate's {{ReflectionHelper}} class to try to load the analyzer class (see [this code|https://github.com/hibernate/hibernate-search/blob/4.1.0.Final/hibernate-search-engine/src/main/java/org/hibernate/search/impl/ConfigContext.java#L179]). The {{ReflectionHelper}} uses the Thread context class loader to try to find the class or (if that fails) the class's class loader; neither of these work in AS7's module system, unless the JARs with the analyzer are defined within the "org.hibernate" module.
> A better solution needs to be found in order for the analyzer class to be specified. Ideally, the solution should be flexible enough so that any AS7 subsystem that uses Hibernate Search can specify the analyzer classname and module.
> See [this forum discussion|https://forum.hibernate.org/viewtopic.php?f=9&t=1015297&sid=fea071c109557fc3ecd4e12bbe53c76d] for discussion and additional context.

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list