Skip to content

Commit

Permalink
Defensive PersistenceExceptionTranslator bean retrieval on shutdown
Browse files Browse the repository at this point in the history
Closes gh-33067
  • Loading branch information
jhoeller committed Jun 18, 2024
1 parent 203fa75 commit 65dbfd0
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,7 @@
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
Expand Down Expand Up @@ -146,7 +147,14 @@ public Object invoke(MethodInvocation mi) throws Throwable {
if (translator == null) {
Assert.state(this.beanFactory != null,
"Cannot use PersistenceExceptionTranslator autodetection without ListableBeanFactory");
translator = detectPersistenceExceptionTranslators(this.beanFactory);
try {
translator = detectPersistenceExceptionTranslators(this.beanFactory);
}
catch (BeanCreationNotAllowedException ex2) {
// Cannot create PersistenceExceptionTranslator bean on shutdown:
// fall back to rethrowing original exception without translation
throw ex;
}
this.persistenceExceptionTranslator = translator;
}
throw DataAccessUtils.translateIfNecessary(ex, translator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test;
Expand All @@ -29,6 +30,7 @@
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.ChainedPersistenceExceptionTranslator;
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.stereotype.Repository;
Expand Down Expand Up @@ -78,10 +80,37 @@ void detectPersistenceExceptionTranslators() throws Throwable {
given(invocation.proceed()).willThrow(exception);

assertThatThrownBy(() -> interceptor.invoke(invocation)).isSameAs(exception);

assertThat(callOrder).containsExactly(10, 20, 30);
}

@Test
void detectPersistenceExceptionTranslatorsOnShutdown() throws Throwable {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
bf.registerBeanDefinition("peti", new RootBeanDefinition(PersistenceExceptionTranslationInterceptor.class));
bf.registerBeanDefinition("pet", new RootBeanDefinition(ChainedPersistenceExceptionTranslator.class));

PersistenceExceptionTranslationInterceptor interceptor =
bf.getBean("peti", PersistenceExceptionTranslationInterceptor.class);
interceptor.setAlwaysTranslate(true);

RuntimeException exception = new RuntimeException();
MethodInvocation invocation = mock();
given(invocation.proceed()).willThrow(exception);

AtomicBoolean correctException = new AtomicBoolean(false);
bf.registerDisposableBean("disposable", () -> {
try {
interceptor.invoke(invocation);
}
catch (Throwable ex) {
correctException.set(ex == exception);
}
});
bf.destroySingletons();
assertThat(correctException).isTrue();
}


private static class CallOrderAwareExceptionTranslator implements PersistenceExceptionTranslator, Ordered {

Expand Down

0 comments on commit 65dbfd0

Please sign in to comment.