Merge branch '6.2.x'
# Conflicts: # spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2025 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.
|
||||||
@@ -45,4 +45,18 @@ public interface PropertyEditorRegistrar {
|
|||||||
*/
|
*/
|
||||||
void registerCustomEditors(PropertyEditorRegistry registry);
|
void registerCustomEditors(PropertyEditorRegistry registry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether this registrar exclusively overrides default editors
|
||||||
|
* rather than registering custom editors, intended to be applied lazily.
|
||||||
|
* <p>This has an impact on registrar handling in a bean factory: see
|
||||||
|
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory#addPropertyEditorRegistrar}.
|
||||||
|
* @since 6.2.3
|
||||||
|
* @see PropertyEditorRegistry#registerCustomEditor
|
||||||
|
* @see PropertyEditorRegistrySupport#overrideDefaultEditor
|
||||||
|
* @see PropertyEditorRegistrySupport#setDefaultEditorRegistrar
|
||||||
|
*/
|
||||||
|
default boolean overridesDefaultEditors() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 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.
|
||||||
@@ -98,6 +98,8 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
|||||||
|
|
||||||
private boolean configValueEditorsActive = false;
|
private boolean configValueEditorsActive = false;
|
||||||
|
|
||||||
|
private @Nullable PropertyEditorRegistrar defaultEditorRegistrar;
|
||||||
|
|
||||||
@SuppressWarnings("NullAway.Init")
|
@SuppressWarnings("NullAway.Init")
|
||||||
private Map<Class<?>, PropertyEditor> defaultEditors;
|
private Map<Class<?>, PropertyEditor> defaultEditors;
|
||||||
|
|
||||||
@@ -149,6 +151,19 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
|||||||
this.configValueEditorsActive = true;
|
this.configValueEditorsActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a registrar for default editors, as a lazy way of overriding default editors.
|
||||||
|
* <p>This is expected to be a collaborator with {@link PropertyEditorRegistrySupport},
|
||||||
|
* downcasting the given {@link PropertyEditorRegistry} accordingly and calling
|
||||||
|
* {@link #overrideDefaultEditor} for registering additional default editors on it.
|
||||||
|
* @param registrar the registrar to call when default editors are actually needed
|
||||||
|
* @since 6.2.3
|
||||||
|
* @see #overrideDefaultEditor
|
||||||
|
*/
|
||||||
|
public void setDefaultEditorRegistrar(PropertyEditorRegistrar registrar) {
|
||||||
|
this.defaultEditorRegistrar = registrar;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the default editor for the specified type with the given property editor.
|
* Override the default editor for the specified type with the given property editor.
|
||||||
* <p>Note that this is different from registering a custom editor in that the editor
|
* <p>Note that this is different from registering a custom editor in that the editor
|
||||||
@@ -176,6 +191,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
|
|||||||
if (!this.defaultEditorsActive) {
|
if (!this.defaultEditorsActive) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (this.overriddenDefaultEditors == null && this.defaultEditorRegistrar != null) {
|
||||||
|
this.defaultEditorRegistrar.registerCustomEditors(this);
|
||||||
|
}
|
||||||
if (this.overriddenDefaultEditors != null) {
|
if (this.overriddenDefaultEditors != null) {
|
||||||
PropertyEditor editor = this.overriddenDefaultEditors.get(requiredType);
|
PropertyEditor editor = this.overriddenDefaultEditors.get(requiredType);
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 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.
|
||||||
@@ -179,7 +179,11 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single
|
|||||||
* on the given registry, fresh for each bean creation attempt. This avoids
|
* on the given registry, fresh for each bean creation attempt. This avoids
|
||||||
* the need for synchronization on custom editors; hence, it is generally
|
* the need for synchronization on custom editors; hence, it is generally
|
||||||
* preferable to use this method instead of {@link #registerCustomEditor}.
|
* preferable to use this method instead of {@link #registerCustomEditor}.
|
||||||
|
* <p>If the given registrar implements
|
||||||
|
* {@link PropertyEditorRegistrar#overridesDefaultEditors()} to return {@code true},
|
||||||
|
* it will be applied lazily (only when default editors are actually needed).
|
||||||
* @param registrar the PropertyEditorRegistrar to register
|
* @param registrar the PropertyEditorRegistrar to register
|
||||||
|
* @see PropertyEditorRegistrar#overridesDefaultEditors()
|
||||||
*/
|
*/
|
||||||
void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
|
void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 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.
|
||||||
@@ -133,6 +133,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
/** Spring ConversionService to use instead of PropertyEditors. */
|
/** Spring ConversionService to use instead of PropertyEditors. */
|
||||||
private @Nullable ConversionService conversionService;
|
private @Nullable ConversionService conversionService;
|
||||||
|
|
||||||
|
/** Default PropertyEditorRegistrars to apply to the beans of this factory. */
|
||||||
|
private final Set<PropertyEditorRegistrar> defaultEditorRegistrars = new LinkedHashSet<>(4);
|
||||||
|
|
||||||
/** Custom PropertyEditorRegistrars to apply to the beans of this factory. */
|
/** Custom PropertyEditorRegistrars to apply to the beans of this factory. */
|
||||||
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
|
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
|
||||||
|
|
||||||
@@ -870,7 +873,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
@Override
|
@Override
|
||||||
public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
|
public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
|
||||||
Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
|
Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
|
||||||
this.propertyEditorRegistrars.add(registrar);
|
if (registrar.overridesDefaultEditors()) {
|
||||||
|
this.defaultEditorRegistrars.add(registrar);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.propertyEditorRegistrars.add(registrar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1098,6 +1106,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
|
setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
|
||||||
setConversionService(otherFactory.getConversionService());
|
setConversionService(otherFactory.getConversionService());
|
||||||
if (otherFactory instanceof AbstractBeanFactory otherAbstractFactory) {
|
if (otherFactory instanceof AbstractBeanFactory otherAbstractFactory) {
|
||||||
|
this.defaultEditorRegistrars.addAll(otherAbstractFactory.defaultEditorRegistrars);
|
||||||
this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
|
this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
|
||||||
this.customEditors.putAll(otherAbstractFactory.customEditors);
|
this.customEditors.putAll(otherAbstractFactory.customEditors);
|
||||||
this.typeConverter = otherAbstractFactory.typeConverter;
|
this.typeConverter = otherAbstractFactory.typeConverter;
|
||||||
@@ -1297,36 +1306,48 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
protected void registerCustomEditors(PropertyEditorRegistry registry) {
|
protected void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||||
if (registry instanceof PropertyEditorRegistrySupport registrySupport) {
|
if (registry instanceof PropertyEditorRegistrySupport registrySupport) {
|
||||||
registrySupport.useConfigValueEditors();
|
registrySupport.useConfigValueEditors();
|
||||||
}
|
if (!this.defaultEditorRegistrars.isEmpty()) {
|
||||||
if (!this.propertyEditorRegistrars.isEmpty()) {
|
// Optimization: lazy overriding of default editors only when needed
|
||||||
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
|
registrySupport.setDefaultEditorRegistrar(new BeanFactoryDefaultEditorRegistrar());
|
||||||
try {
|
|
||||||
registrar.registerCustomEditors(registry);
|
|
||||||
}
|
|
||||||
catch (BeanCreationException ex) {
|
|
||||||
Throwable rootCause = ex.getMostSpecificCause();
|
|
||||||
if (rootCause instanceof BeanCurrentlyInCreationException bce) {
|
|
||||||
String bceBeanName = bce.getBeanName();
|
|
||||||
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
|
|
||||||
"] failed because it tried to obtain currently created bean '" +
|
|
||||||
ex.getBeanName() + "': " + ex.getMessage());
|
|
||||||
}
|
|
||||||
onSuppressedException(ex);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!this.defaultEditorRegistrars.isEmpty()) {
|
||||||
|
// Fallback: proactive overriding of default editors
|
||||||
|
applyEditorRegistrars(registry, this.defaultEditorRegistrars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.propertyEditorRegistrars.isEmpty()) {
|
||||||
|
applyEditorRegistrars(registry, this.propertyEditorRegistrars);
|
||||||
|
}
|
||||||
if (!this.customEditors.isEmpty()) {
|
if (!this.customEditors.isEmpty()) {
|
||||||
this.customEditors.forEach((requiredType, editorClass) ->
|
this.customEditors.forEach((requiredType, editorClass) ->
|
||||||
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
|
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyEditorRegistrars(PropertyEditorRegistry registry, Set<PropertyEditorRegistrar> registrars) {
|
||||||
|
for (PropertyEditorRegistrar registrar : registrars) {
|
||||||
|
try {
|
||||||
|
registrar.registerCustomEditors(registry);
|
||||||
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
Throwable rootCause = ex.getMostSpecificCause();
|
||||||
|
if (rootCause instanceof BeanCurrentlyInCreationException bce) {
|
||||||
|
String bceBeanName = bce.getBeanName();
|
||||||
|
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
|
||||||
|
"] failed because it tried to obtain currently created bean '" +
|
||||||
|
ex.getBeanName() + "': " + ex.getMessage());
|
||||||
|
}
|
||||||
|
onSuppressedException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a merged RootBeanDefinition, traversing the parent bean definition
|
* Return a merged RootBeanDefinition, traversing the parent bean definition
|
||||||
@@ -2075,4 +2096,20 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
final List<MergedBeanDefinitionPostProcessor> mergedDefinition = new ArrayList<>();
|
final List<MergedBeanDefinitionPostProcessor> mergedDefinition = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link PropertyEditorRegistrar} that delegates to the bean factory's
|
||||||
|
* default registrars, adding exception handling for circular reference
|
||||||
|
* scenarios where an editor tries to refer back to the currently created bean.
|
||||||
|
*
|
||||||
|
* @since 6.2.3
|
||||||
|
*/
|
||||||
|
class BeanFactoryDefaultEditorRegistrar implements PropertyEditorRegistrar {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||||
|
applyEditorRegistrars(registry, defaultEditorRegistrars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 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.
|
||||||
@@ -135,4 +135,12 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate the use of {@link PropertyEditorRegistrySupport#overrideDefaultEditor} above.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean overridesDefaultEditors() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user