ExistingSpringTxCompassHelper causes an IllegalAccessError when Compass is running in an Eclipse RCP application that uses Spring.
Eclipse RCP uses separate class loaders (BundleClassLoader) for each plugin. When Compass is bundled as a separate plugin from Spring (this is necessary when the main Eclipse RCP app uses Spring), Compass cannot use a protected access method as is done in ExistingSpringTxCompassHelper, because the Spring object is loaded by another class loader, and you cannot trick separate class loaders into thinking you're part of the same package as a class loaded in another, even when using the same package name..
package org.springframework.transaction.support; // ---------- This trick won't work for Eclipse RCP bundles
public class ExistingSpringTxCompassHelper {
public static boolean isExistingTransaction(PlatformTransactionManager transactionManager) {
if (transactionManager == null) {
return false;
}
AbstractPlatformTransactionManager absTxManager = (AbstractPlatformTransactionManager) transactionManager;
Object transaction = absTxManager.doGetTransaction(); // ----------------- This will throw an IllegalAccessError
return absTxManager.isExistingTransaction(transaction);
}
}
The workaround for now is to extend Compass's SpringSyncTransactionFactory and rewrite the isWithinExistingTransaction method. The correct fix is might be to make the doGetTransaction method public in Spring, though the Spring and Compass teams will know better than I.
Exception is:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compass' defined in class path resource [xxxxxxxxxx.spring.xml]: Invocation of init method failed; nested exception is java.lang.IllegalAccessError: tried to access method org.springframework.transaction.support.AbstractPlatformTransactionManager.doGetTransaction()Ljava/lang/Object; from class org.springframework.transaction.support.ExistingSpringTxCompassHelper
Caused by: java.lang.IllegalAccessError: tried to access method org.springframework.transaction.support.AbstractPlatformTransactionManager.doGetTransaction()Ljava/lang/Object; from class org.springframework.transaction.support.ExistingSpringTxCompassHelper
at org.springframework.transaction.support.ExistingSpringTxCompassHelper.isExistingTransaction(ExistingSpringTxCompassHelper.java:31)
at org.compass.spring.transaction.SpringSyncTransactionFactory.isWithinExistingTransaction(SpringSyncTransactionFactory.java:64)
at org.compass.core.transaction.AbstractTransactionFactory.tryJoinExistingTransaction(AbstractTransactionFactory.java:59)
at org.compass.core.impl.DefaultCompassSession.<init>(DefaultCompassSession.java:94)
at org.compass.core.impl.DefaultCompass.openSession(DefaultCompass.java:186)
at org.compass.core.impl.DefaultCompass.openSession(DefaultCompass.java:170)
at org.compass.core.CompassTemplate.execute(CompassTemplate.java:132)
at org.compass.core.CompassTemplate.execute(CompassTemplate.java:119)
at org.compass.core.impl.DefaultCompass$TransactionalSearchEngineIndexManager.verifyIndex(DefaultCompass.java:291)
at org.compass.core.lucene.engine.manager.ScheduledLuceneSearchEngineIndexManager.verifyIndex(ScheduledLuceneSearchEngineIndexManager.java:98)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:147)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:102)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:95)
at org.compass.core.config.CompassConfiguration.buildCompass(CompassConfiguration.java:192)
at org.compass.spring.LocalCompassBean.newCompass(LocalCompassBean.java:336)
at org.compass.spring.LocalCompassBean.afterPropertiesSet(LocalCompassBean.java:326)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1198)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1167)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:427)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:249)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:155)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:246)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:285)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:122)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:76)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:153)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:504)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:443)
at org.eclipse.equinox.launcher.Main.run(Main.java:1169)
at org.eclipse.equinox.launcher.Main.main(Main.java:1144)
// SpringSyncTransactionFactory
@Override
protected boolean isWithinExistingTransaction( InternalCompassSession session )
throws CompassException { return TransactionSynchronizationManager.isActualTransactionActive(); }
Someone more familiar with Spring internals should be able to determine if that's a suitable replacement for the ExistingSpringTxCompassHelper. It seems to work for me (with Spring managing Hibernate transactions).