Merge branch '6.1.x'
This commit is contained in:
commit
e42c5ca52b
|
@ -823,11 +823,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
/**
|
/**
|
||||||
* This implementation attempts to query the FactoryBean's generic parameter metadata
|
* This implementation attempts to query the FactoryBean's generic parameter metadata
|
||||||
* if present to determine the object type. If not present, i.e. the FactoryBean is
|
* if present to determine the object type. If not present, i.e. the FactoryBean is
|
||||||
* declared as a raw type, checks the FactoryBean's {@code getObjectType} method
|
* declared as a raw type, it checks the FactoryBean's {@code getObjectType} method
|
||||||
* on a plain instance of the FactoryBean, without bean properties applied yet.
|
* on a plain instance of the FactoryBean, without bean properties applied yet.
|
||||||
* If this doesn't return a type yet, and {@code allowInit} is {@code true} a
|
* If this doesn't return a type yet and {@code allowInit} is {@code true}, full
|
||||||
* full creation of the FactoryBean is used as fallback (through delegation to the
|
* creation of the FactoryBean is attempted as fallback (through delegation to the
|
||||||
* superclass's implementation).
|
* superclass implementation).
|
||||||
* <p>The shortcut check for a FactoryBean is only applied in case of a singleton
|
* <p>The shortcut check for a FactoryBean is only applied in case of a singleton
|
||||||
* FactoryBean. If the FactoryBean instance itself is not kept as singleton,
|
* FactoryBean. If the FactoryBean instance itself is not kept as singleton,
|
||||||
* it will be fully created to check the type of its exposed object.
|
* it will be fully created to check the type of its exposed object.
|
||||||
|
|
|
@ -1682,7 +1682,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
* already. The implementation is allowed to instantiate the target factory bean if
|
* already. The implementation is allowed to instantiate the target factory bean if
|
||||||
* {@code allowInit} is {@code true} and the type cannot be determined another way;
|
* {@code allowInit} is {@code true} and the type cannot be determined another way;
|
||||||
* otherwise it is restricted to introspecting signatures and related metadata.
|
* otherwise it is restricted to introspecting signatures and related metadata.
|
||||||
* <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition
|
* <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} is set on the bean definition
|
||||||
* and {@code allowInit} is {@code true}, the default implementation will create
|
* and {@code allowInit} is {@code true}, the default implementation will create
|
||||||
* the FactoryBean via {@code getBean} to call its {@code getObjectType} method.
|
* the FactoryBean via {@code getBean} to call its {@code getObjectType} method.
|
||||||
* Subclasses are encouraged to optimize this, typically by inspecting the generic
|
* Subclasses are encouraged to optimize this, typically by inspecting the generic
|
||||||
|
|
|
@ -29,7 +29,9 @@ import org.springframework.beans.factory.support.AbstractBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -39,8 +41,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* {@link FactoryBean FactoryBeans} defined in the configuration.
|
* {@link FactoryBean FactoryBeans} defined in the configuration.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
class ConfigurationWithFactoryBeanEarlyDeductionTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void preFreezeDirect() {
|
void preFreezeDirect() {
|
||||||
|
@ -82,6 +85,16 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
assertPostFreeze(AttributeClassConfiguration.class);
|
assertPostFreeze(AttributeClassConfiguration.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void preFreezeTargetType() {
|
||||||
|
assertPreFreeze(TargetTypeConfiguration.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void postFreezeTargetType() {
|
||||||
|
assertPostFreeze(TargetTypeConfiguration.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void preFreezeUnresolvedGenericFactoryBean() {
|
void preFreezeUnresolvedGenericFactoryBean() {
|
||||||
// Covers the case where a @Configuration is picked up via component scanning
|
// Covers the case where a @Configuration is picked up via component scanning
|
||||||
|
@ -105,14 +118,13 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertPostFreeze(Class<?> configurationClass) {
|
private void assertPostFreeze(Class<?> configurationClass) {
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configurationClass);
|
||||||
configurationClass);
|
|
||||||
assertContainsMyBeanName(context);
|
assertContainsMyBeanName(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertPreFreeze(Class<?> configurationClass,
|
private void assertPreFreeze(Class<?> configurationClass, BeanFactoryPostProcessor... postProcessors) {
|
||||||
BeanFactoryPostProcessor... postProcessors) {
|
|
||||||
NameCollectingBeanFactoryPostProcessor postProcessor = new NameCollectingBeanFactoryPostProcessor();
|
NameCollectingBeanFactoryPostProcessor postProcessor = new NameCollectingBeanFactoryPostProcessor();
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
try (context) {
|
try (context) {
|
||||||
|
@ -132,41 +144,38 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
assertThat(names).containsExactly("myBean");
|
assertThat(names).containsExactly("myBean");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NameCollectingBeanFactoryPostProcessor
|
|
||||||
implements BeanFactoryPostProcessor {
|
private static class NameCollectingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||||
|
|
||||||
private String[] names;
|
private String[] names;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||||
throws BeansException {
|
ResolvableType typeToMatch = ResolvableType.forClassWithGenerics(MyBean.class, String.class);
|
||||||
this.names = beanFactory.getBeanNamesForType(MyBean.class, true, false);
|
this.names = beanFactory.getBeanNamesForType(typeToMatch, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getNames() {
|
public String[] getNames() {
|
||||||
return this.names;
|
return this.names;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class DirectConfiguration {
|
static class DirectConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
MyBean myBean() {
|
MyBean<String> myBean() {
|
||||||
return new MyBean();
|
return new MyBean<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class GenericMethodConfiguration {
|
static class GenericMethodConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
FactoryBean<MyBean> myBean() {
|
FactoryBean<MyBean<String>> myBean() {
|
||||||
return new TestFactoryBean<>(new MyBean());
|
return new TestFactoryBean<>(new MyBean<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -176,13 +185,11 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
MyFactoryBean myBean() {
|
MyFactoryBean myBean() {
|
||||||
return new MyFactoryBean();
|
return new MyFactoryBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Import(AttributeClassRegistrar.class)
|
@Import(AttributeClassRegistrar.class)
|
||||||
static class AttributeClassConfiguration {
|
static class AttributeClassConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AttributeClassRegistrar implements ImportBeanDefinitionRegistrar {
|
static class AttributeClassRegistrar implements ImportBeanDefinitionRegistrar {
|
||||||
|
@ -191,16 +198,32 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||||
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(
|
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(
|
||||||
RawWithAbstractObjectTypeFactoryBean.class).getBeanDefinition();
|
RawWithAbstractObjectTypeFactoryBean.class).getBeanDefinition();
|
||||||
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, MyBean.class);
|
definition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE,
|
||||||
|
ResolvableType.forClassWithGenerics(MyBean.class, String.class));
|
||||||
registry.registerBeanDefinition("myBean", definition);
|
registry.registerBeanDefinition("myBean", definition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(TargetTypeRegistrar.class)
|
||||||
|
static class TargetTypeConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TargetTypeRegistrar implements ImportBeanDefinitionRegistrar {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||||
|
RootBeanDefinition definition = new RootBeanDefinition(RawWithAbstractObjectTypeFactoryBean.class);
|
||||||
|
definition.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class,
|
||||||
|
ResolvableType.forClassWithGenerics(MyBean.class, String.class)));
|
||||||
|
registry.registerBeanDefinition("myBean", definition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class AbstractMyBean {
|
abstract static class AbstractMyBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MyBean extends AbstractMyBean {
|
static class MyBean<T> extends AbstractMyBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TestFactoryBean<T> implements FactoryBean<T> {
|
static class TestFactoryBean<T> implements FactoryBean<T> {
|
||||||
|
@ -220,31 +243,26 @@ class ConfigurationWithFactoryBeanBeanEarlyDeductionTests {
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return this.instance.getClass();
|
return this.instance.getClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MyFactoryBean extends TestFactoryBean<MyBean> {
|
static class MyFactoryBean extends TestFactoryBean<MyBean<String>> {
|
||||||
|
|
||||||
public MyFactoryBean() {
|
public MyFactoryBean() {
|
||||||
super(new MyBean());
|
super(new MyBean<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class RawWithAbstractObjectTypeFactoryBean implements FactoryBean<Object> {
|
static class RawWithAbstractObjectTypeFactoryBean implements FactoryBean<Object> {
|
||||||
|
|
||||||
private final Object object = new MyBean();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() throws Exception {
|
||||||
return object;
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return MyBean.class;
|
return MyBean.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -39,9 +39,9 @@ import static org.mockito.Mockito.mock;
|
||||||
*/
|
*/
|
||||||
class ResultSetWrappingRowSetTests {
|
class ResultSetWrappingRowSetTests {
|
||||||
|
|
||||||
private ResultSet resultSet = mock();
|
private final ResultSet resultSet = mock();
|
||||||
|
|
||||||
private ResultSetWrappingSqlRowSet rowSet = new ResultSetWrappingSqlRowSet(resultSet);
|
private final ResultSetWrappingSqlRowSet rowSet = new ResultSetWrappingSqlRowSet(resultSet);
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -198,6 +198,7 @@ class ResultSetWrappingRowSetTests {
|
||||||
doTest(rset, rowset, "test", true);
|
doTest(rset, rowset, "test", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void doTest(Method rsetMethod, Method rowsetMethod, Object arg, Object ret) throws Exception {
|
private void doTest(Method rsetMethod, Method rowsetMethod, Object arg, Object ret) throws Exception {
|
||||||
if (arg instanceof String) {
|
if (arg instanceof String) {
|
||||||
given(resultSet.findColumn((String) arg)).willReturn(1);
|
given(resultSet.findColumn((String) arg)).willReturn(1);
|
||||||
|
@ -207,9 +208,9 @@ class ResultSetWrappingRowSetTests {
|
||||||
given(rsetMethod.invoke(resultSet, arg)).willReturn(ret).willThrow(new SQLException("test"));
|
given(rsetMethod.invoke(resultSet, arg)).willReturn(ret).willThrow(new SQLException("test"));
|
||||||
}
|
}
|
||||||
rowsetMethod.invoke(rowSet, arg);
|
rowsetMethod.invoke(rowSet, arg);
|
||||||
assertThatExceptionOfType(InvocationTargetException.class).isThrownBy(() ->
|
assertThatExceptionOfType(InvocationTargetException.class)
|
||||||
rowsetMethod.invoke(rowSet, arg)).
|
.isThrownBy(() -> rowsetMethod.invoke(rowSet, arg))
|
||||||
satisfies(ex -> assertThat(ex.getTargetException()).isExactlyInstanceOf(InvalidResultSetAccessException.class));
|
.satisfies(ex -> assertThat(ex.getTargetException()).isExactlyInstanceOf(InvalidResultSetAccessException.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DefaultTransactionAttribute, with default settings.
|
* Create a new {@code DefaultTransactionAttribute} with default settings.
|
||||||
* Can be modified through bean property setters.
|
* Can be modified through bean property setters.
|
||||||
* @see #setPropagationBehavior
|
* @see #setPropagationBehavior
|
||||||
* @see #setIsolationLevel
|
* @see #setIsolationLevel
|
||||||
|
@ -75,7 +75,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DefaultTransactionAttribute with the given
|
* Create a new {@code DefaultTransactionAttribute} with the given
|
||||||
* propagation behavior. Can be modified through bean property setters.
|
* propagation behavior. Can be modified through bean property setters.
|
||||||
* @param propagationBehavior one of the propagation constants in the
|
* @param propagationBehavior one of the propagation constants in the
|
||||||
* TransactionDefinition interface
|
* TransactionDefinition interface
|
||||||
|
|
|
@ -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");
|
* 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.
|
||||||
|
@ -234,11 +234,13 @@ public abstract class AbstractReactiveTransactionManager
|
||||||
prepareSynchronization(synchronizationManager, status, definition)).thenReturn(status);
|
prepareSynchronization(synchronizationManager, status, definition)).thenReturn(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
|
// PROPAGATION_REQUIRED, PROPAGATION_SUPPORTS, PROPAGATION_MANDATORY:
|
||||||
|
// regular participation in existing transaction.
|
||||||
if (debugEnabled) {
|
if (debugEnabled) {
|
||||||
logger.debug("Participating in existing transaction");
|
logger.debug("Participating in existing transaction");
|
||||||
}
|
}
|
||||||
return Mono.just(prepareReactiveTransaction(synchronizationManager, definition, transaction, false, debugEnabled, null));
|
return Mono.just(prepareReactiveTransaction(
|
||||||
|
synchronizationManager, definition, transaction, false, debugEnabled, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -491,7 +491,8 @@ public abstract class AbstractPlatformTransactionManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
|
// PROPAGATION_REQUIRED, PROPAGATION_SUPPORTS, PROPAGATION_MANDATORY:
|
||||||
|
// regular participation in existing transaction.
|
||||||
if (debugEnabled) {
|
if (debugEnabled) {
|
||||||
logger.debug("Participating in existing transaction");
|
logger.debug("Participating in existing transaction");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* 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.
|
||||||
|
@ -90,7 +90,7 @@ public class DefaultTransactionDefinition implements TransactionDefinition, Seri
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DefaultTransactionDefinition, with default settings.
|
* Create a new {@code DefaultTransactionDefinition} with default settings.
|
||||||
* Can be modified through bean property setters.
|
* Can be modified through bean property setters.
|
||||||
* @see #setPropagationBehavior
|
* @see #setPropagationBehavior
|
||||||
* @see #setIsolationLevel
|
* @see #setIsolationLevel
|
||||||
|
@ -118,7 +118,7 @@ public class DefaultTransactionDefinition implements TransactionDefinition, Seri
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DefaultTransactionDefinition with the given
|
* Create a new {@code DefaultTransactionDefinition} with the given
|
||||||
* propagation behavior. Can be modified through bean property setters.
|
* propagation behavior. Can be modified through bean property setters.
|
||||||
* @param propagationBehavior one of the propagation constants in the
|
* @param propagationBehavior one of the propagation constants in the
|
||||||
* TransactionDefinition interface
|
* TransactionDefinition interface
|
||||||
|
|
Loading…
Reference in New Issue