[
https://hibernate.onjira.com/browse/HSEARCH-1115?page=com.atlassian.jira....
]
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/hiber...]).
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&am...]
for discussion and additional context.
--
This message is automatically generated by JIRA.
For more information on JIRA, see:
http://www.atlassian.com/software/jira