New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Could not autowire @Configurable bean when running testng tests with two contexts [SPR-16227] #20775
Comments
Stéphane Nicoll commented Spring Boot issues (the use of slice test annotation) are not handled in this issue tracker. Rather than the analysis with bits of code, please share a sample that we can run as it is the most effective way to make sure we're on the same page. Once you have that, create an issue in the Spring Boot tracker |
Andy Wilkinson commented I think this should be re-opened as the problem occurs without Spring Boot being involved. Here's a fork of the sample which reproduces the problem without Spring Boot's involvement: https://github.com/wilkinsona/spring-boot-issue-11123. |
Andy Wilkinson commented I believe that spring-projects/spring-boot#11461, while exhibiting a different symptom, has the same underlying cause where the Framework's using a stale bean factory. |
Łukasz Świątek commented I encounterd the same problem and one of my team mates, came up with custom test listener to bypass this problem
public class ReinitConfigurableAspectTestExecutionListener extends AbstractTestExecutionListener {
private static final Logger log = LoggerFactory.getLogger(ReinitConfigurableAspectTestExecutionListener.class);
@Configurable
public static class TestClass implements BeanFactoryAware {
BeanFactory bf;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.bf = beanFactory;
}
}
@SuppressWarnings("resource")
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
try {
ApplicationContext appCtx = testContext.getApplicationContext();
AnnotationBeanConfigurerAspect configurableAspect = appCtx.getBean(AnnotationBeanConfigurerAspect.class);
TestClass testBean1 = new TestClass();
int originalhc = System.identityHashCode(testBean1.bf);
if (appCtx instanceof ConfigurableApplicationContext) {
ConfigurableApplicationContext configurableAppCtx = (ConfigurableApplicationContext) appCtx;
ConfigurableListableBeanFactory bf = configurableAppCtx.getBeanFactory();
configurableAspect.setBeanFactory(bf);
int targethc = System.identityHashCode(bf);
TestClass testBean2 = new TestClass();
int newhc = System.identityHashCode(testBean2.bf);
if (newhc != targethc) {
log.error("Switch FAIL : {} => {} (is {})", originalhc, targethc, newhc);
} else {
log.info("Switch OK : {} => {}", originalhc, newhc);
}
} else {
log.warn("Test application context not an instance of of ConfigurableApplicationContext, was :"
+ appCtx.getClass());
}
} catch (NoSuchBeanDefinitionException exc) {
log.warn("No AnnotationBeanConfigurerAspect bean defined in context, skipping");
}
}
} while this is just a bypass, it might be usefull when next person googles this problem |
cda commented Also found an issue with transaction manager that seems related, using the same environment. This causes inconsistent entity manager behavior (dual context vs single context). The odd thing I found while debugging is that transaction manager cache contains an invalid transaction manager: TransactionAspectSupport.java(line 380) (spring-tx-4.3.14.RELEASE) PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
-> if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
} In the above code, when reaching the marked line, defaultTransactionManager contains a different transaction manager from this.beanFactory.getBean(PlatformTransactionManager.class), because the beanFactory has been changed. I think this issue should be rename as it is broader. I am currently having second thoughts about using Spring with AspectJ as this is the third issue I discover. |
As a workaround for transaction manager issue above, I added the following to the workaround of Łukasz Świątek:
|
cda opened SPR-16227 and commented
Environment: Spring boot 1.5.8.RELEASE, TestNg 6.11
Use case:
Aspects are weaved at compile time.
I run a set of tests, having some classes annotated with
@SpringBootTest
, and one with@WebMvcTest
.From my investigation:
Tests run fine with first application context made for tests with
@SpringBootTest
, but reaching the class with@WebMvcTest
, a new context is created, with a new bean factory.When configuring the new context, a AnnotationBeanConfigurerAspect bean is requested from SpringConfiguredConfiguration.beanConfigurerAspect():
AnnotationBeanConfigurerAspect.aspectOf() resturns the same instance (singleton pattern) as the previous context was using:
(decompiled code)
After returning the same AnnotationBeanConfigurerAspect instance, the old context bean factory from the BeanConfigurerSupport member is replaced with the newly created one:
Testing continues for other
@SpringBootTest
classes, and it fails autowiring@Configurable
object, due to replaced bean factory, with the following stack trace:Affects: 4.3.12
0 votes, 5 watchers
The text was updated successfully, but these errors were encountered: