Skip to content

Commit

Permalink
Sort detected PersistenceExceptionTranslator
Browse files Browse the repository at this point in the history
Apply sorting on detected PersistenceExceptionTranslators.

Relates to spring-projects#24634
  • Loading branch information
ttddyy committed Mar 26, 2020
1 parent ac11acb commit 4b09631
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package org.springframework.dao.support;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
Expand All @@ -27,6 +30,8 @@
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.OrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
Expand Down Expand Up @@ -167,8 +172,21 @@ protected PersistenceExceptionTranslator detectPersistenceExceptionTranslators(L
// Find all translators, being careful not to activate FactoryBeans.
Map<String, PersistenceExceptionTranslator> pets = BeanFactoryUtils.beansOfTypeIncludingAncestors(
beanFactory, PersistenceExceptionTranslator.class, false, false);

List<PersistenceExceptionTranslator> translators = new ArrayList<>(pets.values());
if (translators.size() > 1) {
Comparator<Object> comparatorToUse = null;
if (beanFactory instanceof DefaultListableBeanFactory) {
comparatorToUse = ((DefaultListableBeanFactory) beanFactory).getDependencyComparator();
}
if (comparatorToUse == null) {
comparatorToUse = OrderComparator.INSTANCE;
}
translators.sort(comparatorToUse);
}

ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator();
for (PersistenceExceptionTranslator pet : pets.values()) {
for (PersistenceExceptionTranslator pet : translators) {
cpet.addDelegate(pet);
}
return cpet;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2020 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 @@ -16,19 +16,34 @@

package org.springframework.dao.annotation;

import java.util.ArrayList;
import java.util.List;

import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslationInterceptor;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.stereotype.Repository;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

/**
* Tests for standalone usage of a PersistenceExceptionTranslationInterceptor, as explicit advice bean in a BeanFactory
* rather than applied as part of a PersistenceExceptionTranslationAdvisor.
*
* @author Juergen Hoeller
* @author Tadaya Tsuyukubo
*/
public class PersistenceExceptionTranslationInterceptorTests extends PersistenceExceptionTranslationAdvisorTests {

Expand All @@ -42,4 +57,50 @@ protected void addPersistenceExceptionTranslation(ProxyFactory pf, PersistenceEx
}
}

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

List<Integer> callOrder = new ArrayList<>();
bf.registerSingleton("pet20", new CallOrderAwareExceptionTranslator(20, callOrder));
bf.registerSingleton("pet10", new CallOrderAwareExceptionTranslator(10, callOrder));
bf.registerSingleton("pet30", new CallOrderAwareExceptionTranslator(30, callOrder));

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

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

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

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

private static class CallOrderAwareExceptionTranslator implements PersistenceExceptionTranslator, Ordered {

private final int order;

private final List<Integer> callOrder;

public CallOrderAwareExceptionTranslator(int order, List<Integer> callOrder) {
this.order = order;
this.callOrder = callOrder;
}

@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
callOrder.add(this.order);
return null;
}

@Override
public int getOrder() {
return this.order;
}
}

}

0 comments on commit 4b09631

Please sign in to comment.