Browse Source

Fail early FactoryBean instantiation for LinkageError

Closes gh-26425

(cherry picked from commit defc2466b0)
pull/26558/head
Juergen Hoeller 5 years ago
parent
commit
27c5480c82
  1. 7
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  2. 70
      spring-context/src/test/java/org/springframework/context/annotation/AggressiveFactoryBeanInstantiationTests.java

7
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -1013,6 +1013,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
throw ex; throw ex;
} }
catch (BeanCreationException ex) { catch (BeanCreationException ex) {
// Don't swallow a linkage error since it contains a full stacktrace on
// first occurrence... and just a plain NoClassDefFoundError afterwards.
if (ex.contains(LinkageError.class)) {
throw ex;
}
// Instantiation failure, maybe too early... // Instantiation failure, maybe too early...
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex); logger.debug("Bean creation exception on singleton FactoryBean type check: " + ex);

70
spring-context/src/test/java/org/springframework/context/annotation/AggressiveFactoryBeanInstantiationTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,14 +16,23 @@
package org.springframework.context.annotation; package org.springframework.context.annotation;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
/** /**
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Liu Dongmiao
*/ */
public class AggressiveFactoryBeanInstantiationTests { public class AggressiveFactoryBeanInstantiationTests {
@ -49,17 +58,66 @@ public class AggressiveFactoryBeanInstantiationTests {
} }
} }
@Test
public void checkLinkageError() {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
context.register(BeanMethodConfigurationWithExceptionInInitializer.class);
context.refresh();
fail("Should have thrown BeanCreationException");
}
catch (BeanCreationException ex) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
ex.printStackTrace(pw);
pw.flush();
String stackTrace = baos.toString();
assertThat(stackTrace.contains(".<clinit>")).isTrue();
assertThat(stackTrace.contains("java.lang.NoClassDefFoundError")).isFalse();
}
}
@Configuration @Configuration
static class BeanMethodConfiguration { static class BeanMethodConfiguration {
@Bean @Bean
public String foo() {
return "foo";
}
@Bean
public AutowiredBean autowiredBean() {
return new AutowiredBean();
}
@Bean
@DependsOn("autowiredBean")
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) { public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
return new SimpleFactoryBean(applicationContext); return new SimpleFactoryBean(applicationContext);
} }
} }
@Configuration
static class BeanMethodConfigurationWithExceptionInInitializer extends BeanMethodConfiguration {
@Bean
@DependsOn("autowiredBean")
@Override
public SimpleFactoryBean simpleFactoryBean(ApplicationContext applicationContext) {
new ExceptionInInitializer();
return new SimpleFactoryBean(applicationContext);
}
}
static class AutowiredBean {
@Autowired
String foo;
}
static class SimpleFactoryBean implements FactoryBean<Object> { static class SimpleFactoryBean implements FactoryBean<Object> {
public SimpleFactoryBean(ApplicationContext applicationContext) { public SimpleFactoryBean(ApplicationContext applicationContext) {
@ -76,4 +134,14 @@ public class AggressiveFactoryBeanInstantiationTests {
} }
} }
static class ExceptionInInitializer {
private static final int ERROR = callInClinit();
private static int callInClinit() {
throw new UnsupportedOperationException();
}
}
} }

Loading…
Cancel
Save