This is an automated email from the ASF dual-hosted git repository. garydgregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-configuration.git
commit c1695dd50bab56c52bc3cc203f7b37d9d2265674 Author: Gary Gregory <[email protected]> AuthorDate: Sat Aug 22 11:40:08 2026 -0400 Fix SpotBugs USO_UNSAFE_METHOD_SYNCHRONIZATION in MultiFileConfigurationBuilder. --- src/changes/changes.xml | 1 + .../combined/MultiFileConfigurationBuilder.java | 46 +++++++++++++--------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f043f7447..fac3b9088 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -29,6 +29,7 @@ <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix SpotBugs USO_UNSAFE_METHOD_SYNCHRONIZATION in BasicConfigurationBuilder.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix SpotBugs USO_UNSAFE_METHOD_SYNCHRONIZATION in CombinedConfigurationBuilder.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix SpotBugs USO_UNSAFE_METHOD_SYNCHRONIZATION in FileBasedConfigurationBuilder.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix SpotBugs USO_UNSAFE_METHOD_SYNCHRONIZATION in MultiFileConfigurationBuilder.</action> <!-- ADD --> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Gary Gregory">Bump org.apache.commons:commons-parent from 100 to 103.</action> diff --git a/src/main/java/org/apache/commons/configuration2/builder/combined/MultiFileConfigurationBuilder.java b/src/main/java/org/apache/commons/configuration2/builder/combined/MultiFileConfigurationBuilder.java index 416601bc0..07bce2846 100644 --- a/src/main/java/org/apache/commons/configuration2/builder/combined/MultiFileConfigurationBuilder.java +++ b/src/main/java/org/apache/commons/configuration2/builder/combined/MultiFileConfigurationBuilder.java @@ -128,6 +128,11 @@ public class MultiFileConfigurationBuilder<T extends FileBasedConfiguration> ext */ private final EventListener<ConfigurationBuilderEvent> managedBuilderDelegationListener = this::handleManagedBuilderEvent; + /** + * A lock object for synchronizing access. + */ + private final Object lock = new Object(); + /** * Creates a new instance of {@code MultiFileConfigurationBuilder} without setting initialization parameters. * @@ -168,11 +173,13 @@ public class MultiFileConfigurationBuilder<T extends FileBasedConfiguration> ext * the internally used configuration builders. */ @Override - public synchronized <E extends Event> void addEventListener(final EventType<E> eventType, final EventListener<? super E> l) { - super.addEventListener(eventType, l); - if (isEventTypeForManagedBuilders(eventType)) { - getManagedBuilders().values().forEach(b -> b.addEventListener(eventType, l)); - configurationListeners.addEventListener(eventType, l); + public <E extends Event> void addEventListener(final EventType<E> eventType, final EventListener<? super E> l) { + synchronized (lock) { + super.addEventListener(eventType, l); + if (isEventTypeForManagedBuilders(eventType)) { + getManagedBuilders().values().forEach(b -> b.addEventListener(eventType, l)); + configurationListeners.addEventListener(eventType, l); + } } } @@ -392,27 +399,30 @@ public class MultiFileConfigurationBuilder<T extends FileBasedConfiguration> ext } /** - * {@inheritDoc} This implementation ensures that the listener is also removed from managed configuration builders if - * necessary. + * {@inheritDoc} This implementation ensures that the listener is also removed from managed configuration builders if necessary. */ @Override - public synchronized <E extends Event> boolean removeEventListener(final EventType<E> eventType, final EventListener<? super E> l) { - final boolean result = super.removeEventListener(eventType, l); - if (isEventTypeForManagedBuilders(eventType)) { - getManagedBuilders().values().forEach(b -> b.removeEventListener(eventType, l)); - configurationListeners.removeEventListener(eventType, l); + public <E extends Event> boolean removeEventListener(final EventType<E> eventType, final EventListener<? super E> l) { + synchronized (lock) { + final boolean result = super.removeEventListener(eventType, l); + if (isEventTypeForManagedBuilders(eventType)) { + getManagedBuilders().values().forEach(b -> b.removeEventListener(eventType, l)); + configurationListeners.removeEventListener(eventType, l); + } + return result; } - return result; } /** * {@inheritDoc} This implementation clears the cache with all managed builders. */ @Override - public synchronized void resetParameters() { - getManagedBuilders().values().forEach(b -> b.removeEventListener(ConfigurationBuilderEvent.ANY, managedBuilderDelegationListener)); - getManagedBuilders().clear(); - interpolator.set(null); - super.resetParameters(); + public void resetParameters() { + synchronized (lock) { + getManagedBuilders().values().forEach(b -> b.removeEventListener(ConfigurationBuilderEvent.ANY, managedBuilderDelegationListener)); + getManagedBuilders().clear(); + interpolator.set(null); + super.resetParameters(); + } } }
