You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2024/12/18 22:13:56 UTC
(commons-beanutils) 01/03: Bump commons-collections4 from 4.5.0-M2 to 4.5.0-M3
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-beanutils.git
commit db3cbe0e298d1e0a2de44774db8d80de04e97044
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Dec 18 17:07:03 2024 -0500
Bump commons-collections4 from 4.5.0-M2 to 4.5.0-M3
---
pom.xml | 3 +-
src/changes/changes.xml | 2 +-
.../org/apache/commons/beanutils2/BeanUtils.java | 27 +-
.../commons/beanutils2/ConvertUtilsBean.java | 5 +-
.../commons/beanutils2/PropertyUtilsBean.java | 10 +-
.../apache/commons/beanutils2/WeakFastHashMap.java | 711 ---------------------
.../beanutils2/locale/LocaleConvertUtilsBean.java | 15 +-
.../org/apache/commons/beanutils2/BeanMapTest.java | 37 +-
8 files changed, 49 insertions(+), 761 deletions(-)
diff --git a/pom.xml b/pom.xml
index 4c591b22..de34ee6a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,7 +65,7 @@
<commons.jacoco.complexityRatio>0.61</commons.jacoco.complexityRatio>
<commons.jacoco.lineRatio>0.72</commons.jacoco.lineRatio>
<!-- Dependencies -->
- <commons.collections.version>4.5.0-M2</commons.collections.version>
+ <commons.collections.version>4.5.0-M3-SNAPSHOT</commons.collections.version>
</properties>
<issueManagement>
@@ -102,7 +102,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${commons.collections.version}</version>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 205a9363..95fc3e48 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -104,7 +104,7 @@
Fix SpotBugs [ERROR] Medium: org.apache.commons.beanutils2.WrapDynaClass.getDynaProperties() may expose internal representation by returning WrapDynaClass.properties [org.apache.commons.beanutils2.WrapDynaClass] At WrapDynaClass.java:[line 172] EI_EXPOSE_REP.
</action>
<action dev="ggregory" type="fix" due-to="Melloware, sebbASF, Gary Gregory, Michal Landsman">
- Replace Commons Collections Test Framework 3.2.2 with 4.5.0-M2 #40.
+ Replace Commons Collections Test Framework 3.2.2 with 4.5.0-M3 #40.
</action>
<action dev="ggregory" type="fix" due-to="Gary Gregory">
Provide error index in ConversionException message in DateTimeConverter.parse(Class, Class, String, DateFormat).
diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java
index d19c22c7..2def8ed2 100644
--- a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java
+++ b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java
@@ -20,6 +20,8 @@ package org.apache.commons.beanutils2;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
+import org.apache.commons.collections4.map.ConcurrentReferenceHashMap;
+
/**
* <p>
* Utility methods for populating JavaBeans properties via reflection.
@@ -32,7 +34,6 @@ import java.util.Map;
*
* @see BeanUtilsBean
*/
-
public class BeanUtils {
/** An empty class array */
@@ -43,7 +44,7 @@ public class BeanUtils {
/**
* <p>
- * Clone a bean based on the available property getters and setters, even if the bean class itself does not implement Cloneable.
+ * Clones a bean based on the available property getters and setters, even if the bean class itself does not implement Cloneable.
* </p>
*
* <p>
@@ -59,14 +60,12 @@ public class BeanUtils {
* @see BeanUtilsBean#cloneBean
*/
public static Object cloneBean(final Object bean) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().cloneBean(bean);
-
}
/**
* <p>
- * Copy property values from the origin bean to the destination bean for all cases where the property names are the same.
+ * Copies property values from the origin bean to the destination bean for all cases where the property names are the same.
* </p>
*
* <p>
@@ -82,7 +81,6 @@ public class BeanUtils {
* @see BeanUtilsBean#copyProperties
*/
public static void copyProperties(final Object dest, final Object orig) throws IllegalAccessException, InvocationTargetException {
-
BeanUtilsBean.getInstance().copyProperties(dest, orig);
}
@@ -103,12 +101,11 @@ public class BeanUtils {
* @see BeanUtilsBean#copyProperty
*/
public static void copyProperty(final Object bean, final String name, final Object value) throws IllegalAccessException, InvocationTargetException {
-
BeanUtilsBean.getInstance().copyProperty(bean, name, value);
}
/**
- * Create a cache.
+ * Creates a cache.
*
* @param <K> the key type of the cache
* @param <V> the value type of the cache
@@ -116,7 +113,8 @@ public class BeanUtils {
* @since 1.8.0
*/
public static <K, V> Map<K, V> createCache() {
- return new WeakFastHashMap<>();
+ return ConcurrentReferenceHashMap.<K, V>builder().get();
+ // return new ConcurrentHashMap<>();
}
/**
@@ -136,7 +134,6 @@ public class BeanUtils {
* @see BeanUtilsBean#describe
*/
public static Map<String, String> describe(final Object bean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().describe(bean);
}
@@ -159,7 +156,6 @@ public class BeanUtils {
*/
public static String[] getArrayProperty(final Object bean, final String name)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getArrayProperty(bean, name);
}
@@ -182,7 +178,6 @@ public class BeanUtils {
*/
public static String getIndexedProperty(final Object bean, final String name)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getIndexedProperty(bean, name);
}
@@ -206,7 +201,6 @@ public class BeanUtils {
*/
public static String getIndexedProperty(final Object bean, final String name, final int index)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getIndexedProperty(bean, name, index);
}
@@ -230,7 +224,6 @@ public class BeanUtils {
*/
public static String getMappedProperty(final Object bean, final String name)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getMappedProperty(bean, name);
}
@@ -255,7 +248,6 @@ public class BeanUtils {
*/
public static String getMappedProperty(final Object bean, final String name, final String key)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getMappedProperty(bean, name, key);
}
@@ -280,7 +272,6 @@ public class BeanUtils {
*/
public static String getNestedProperty(final Object bean, final String name)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getNestedProperty(bean, name);
}
@@ -303,7 +294,6 @@ public class BeanUtils {
* @see BeanUtilsBean#getProperty
*/
public static String getProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getProperty(bean, name);
}
@@ -327,7 +317,6 @@ public class BeanUtils {
*/
public static String getSimpleProperty(final Object bean, final String name)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-
return BeanUtilsBean.getInstance().getSimpleProperty(bean, name);
}
@@ -348,7 +337,6 @@ public class BeanUtils {
* @see BeanUtilsBean#populate
*/
public static void populate(final Object bean, final Map<String, ? extends Object> properties) throws IllegalAccessException, InvocationTargetException {
-
BeanUtilsBean.getInstance().populate(bean, properties);
}
@@ -369,7 +357,6 @@ public class BeanUtils {
* @see BeanUtilsBean#setProperty
*/
public static void setProperty(final Object bean, final String name, final Object value) throws IllegalAccessException, InvocationTargetException {
-
BeanUtilsBean.getInstance().setProperty(bean, name, value);
}
}
diff --git a/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java
index d1c2d26f..5b33c32d 100644
--- a/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java
@@ -45,6 +45,7 @@ import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Collection;
import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.regex.Pattern;
@@ -215,13 +216,11 @@ public class ConvertUtilsBean {
/**
* The set of {@link Converter}s that can be used to convert Strings into objects of a specified Class, keyed by the destination Class.
*/
- private final WeakFastHashMap<Class<?>, Converter<?>> converters = new WeakFastHashMap<>();
+ private final Map<Class<?>, Converter<?>> converters = BeanUtils.createCache();
/** Constructs a bean with standard converters registered */
public ConvertUtilsBean() {
- converters.setFast(false);
deregister();
- converters.setFast(true);
}
/**
diff --git a/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
index b8620f2e..54767948 100644
--- a/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/PropertyUtilsBean.java
@@ -112,19 +112,17 @@ public class PropertyUtilsBean {
/**
* The cache of PropertyDescriptor arrays for beans we have already introspected, keyed by the java.lang.Class of this object.
*/
- private final WeakFastHashMap<Class<?>, BeanIntrospectionData> descriptorsCache;
+ private final Map<Class<?>, BeanIntrospectionData> descriptorsCache;
- private final WeakFastHashMap<Class<?>, Map> mappedDescriptorsCache;
+ private final Map<Class<?>, Map> mappedDescriptorsCache;
/** The list with BeanIntrospector objects. */
private final List<BeanIntrospector> introspectors;
/** Base constructor */
public PropertyUtilsBean() {
- descriptorsCache = new WeakFastHashMap<>();
- descriptorsCache.setFast(true);
- mappedDescriptorsCache = new WeakFastHashMap<>();
- mappedDescriptorsCache.setFast(true);
+ descriptorsCache = BeanUtils.createCache();
+ mappedDescriptorsCache = BeanUtils.createCache();
introspectors = new CopyOnWriteArrayList<>();
resetBeanIntrospectors();
}
diff --git a/src/main/java/org/apache/commons/beanutils2/WeakFastHashMap.java b/src/main/java/org/apache/commons/beanutils2/WeakFastHashMap.java
deleted file mode 100644
index 333a35b8..00000000
--- a/src/main/java/org/apache/commons/beanutils2/WeakFastHashMap.java
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.beanutils2;
-
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-
-/**
- * <p>
- * A customized implementation of {@link java.util.HashMap} designed to operate in a multi-threaded environment where the large majority of method calls are
- * read-only, instead of structural changes. When operating in "fast" mode, read calls are non-synchronized and write calls perform the following steps:
- * </p>
- * <ul>
- * <li>Clone the existing collection
- * <li>Perform the modification on the clone
- * <li>Replace the existing collection with the (modified) clone
- * </ul>
- * <p>
- * When first created, objects of this class default to "slow" mode, where all accesses of any type are synchronized but no cloning takes place. This is
- * appropriate for initially populating the collection, followed by a switch to "fast" mode (by calling {@code setFast(true)}) after initialization is complete.
- * </p>
- *
- * <p>
- * <strong>NOTE</strong>: If you are creating and accessing a {@code HashMap} only within a single thread, you should use {@link java.util.HashMap} directly
- * (with no synchronization), for maximum performance.
- * </p>
- *
- * <p>
- * <strong>NOTE</strong>: <i>This class is not cross-platform. Using it may cause unexpected failures on some architectures.</i> It suffers from the same
- * problems as the double-checked locking idiom. In particular, the instruction that clones the internal collection and the instruction that sets the internal
- * reference to the clone can be executed or perceived out-of-order. This means that any read operation might fail unexpectedly, as it may be reading the state
- * of the internal collection before the internal collection is fully formed. For more information on the double-checked locking idiom, see the
- * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html"> Double-Checked Locking Idiom Is Broken Declaration</a>.
- * </p>
- *
- * Copied from Commons Collections 1.0
- *
- * @param <K> the key
- * @param <V> the value
- */
-public class WeakFastHashMap<K, V> extends HashMap<K, V> {
-
- /**
- * Abstract collection implementation shared by keySet(), values() and entrySet().
- *
- * @param <E> the element type
- */
- private abstract class AbstractCollectionView<E> implements Collection<E> {
-
- private final class CollectionViewIterator implements Iterator<E> {
-
- private Map<K, V> expected;
- private Map.Entry<K, V> lastReturned;
- private final Iterator<Map.Entry<K, V>> iterator;
-
- public CollectionViewIterator() {
- this.expected = map;
- this.iterator = expected.entrySet().iterator();
- }
-
- @Override
- public boolean hasNext() {
- if (expected != map) {
- throw new ConcurrentModificationException();
- }
- return iterator.hasNext();
- }
-
- @Override
- public E next() {
- if (expected != map) {
- throw new ConcurrentModificationException();
- }
- lastReturned = iterator.next();
- return iteratorNext(lastReturned);
- }
-
- @Override
- public void remove() {
- if (lastReturned == null) {
- throw new IllegalStateException();
- }
- if (fast) {
- synchronized (WeakFastHashMap.this) {
- if (expected != map) {
- throw new ConcurrentModificationException();
- }
- WeakFastHashMap.this.remove(lastReturned.getKey());
- lastReturned = null;
- expected = map;
- }
- } else {
- iterator.remove();
- lastReturned = null;
- }
- }
- }
-
- public AbstractCollectionView() {
- }
-
- @Override
- public boolean add(final E o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(final Collection<? extends E> c) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- if (fast) {
- synchronized (WeakFastHashMap.this) {
- map = createMap();
- }
- } else {
- synchronized (map) {
- get(map).clear();
- }
- }
- }
-
- @Override
- public boolean contains(final Object o) {
- if (fast) {
- return get(map).contains(o);
- }
- synchronized (map) {
- return get(map).contains(o);
- }
- }
-
- @Override
- public boolean containsAll(final Collection<?> o) {
- if (fast) {
- return get(map).containsAll(o);
- }
- synchronized (map) {
- return get(map).containsAll(o);
- }
- }
-
- @Override
- public boolean equals(final Object o) {
- if (o == this) {
- return true;
- }
- if (fast) {
- return get(map).equals(o);
- }
- synchronized (map) {
- return get(map).equals(o);
- }
- }
-
- protected abstract Collection<E> get(Map<K, V> map);
-
- @Override
- public int hashCode() {
- if (fast) {
- return get(map).hashCode();
- }
- synchronized (map) {
- return get(map).hashCode();
- }
- }
-
- @Override
- public boolean isEmpty() {
- if (fast) {
- return get(map).isEmpty();
- }
- synchronized (map) {
- return get(map).isEmpty();
- }
- }
-
- @Override
- public Iterator<E> iterator() {
- return new CollectionViewIterator();
- }
-
- protected abstract E iteratorNext(Map.Entry<K, V> entry);
-
- @Override
- public boolean remove(final Object o) {
- if (fast) {
- synchronized (WeakFastHashMap.this) {
- final Map<K, V> temp = cloneMap(map);
- final boolean r = get(temp).remove(o);
- map = temp;
- return r;
- }
- }
- synchronized (map) {
- return get(map).remove(o);
- }
- }
-
- @Override
- public boolean removeAll(final Collection<?> o) {
- if (fast) {
- synchronized (WeakFastHashMap.this) {
- final Map<K, V> temp = cloneMap(map);
- final boolean r = get(temp).removeAll(o);
- map = temp;
- return r;
- }
- }
- synchronized (map) {
- return get(map).removeAll(o);
- }
- }
-
- @Override
- public boolean retainAll(final Collection<?> o) {
- if (fast) {
- synchronized (WeakFastHashMap.this) {
- final Map<K, V> temp = cloneMap(map);
- final boolean r = get(temp).retainAll(o);
- map = temp;
- return r;
- }
- }
- synchronized (map) {
- return get(map).retainAll(o);
- }
- }
-
- @Override
- public int size() {
- if (fast) {
- return get(map).size();
- }
- synchronized (map) {
- return get(map).size();
- }
- }
-
- @Override
- public Object[] toArray() {
- if (fast) {
- return get(map).toArray();
- }
- synchronized (map) {
- return get(map).toArray();
- }
- }
-
- @Override
- public <T> T[] toArray(final T[] o) {
- if (fast) {
- return get(map).toArray(o);
- }
- synchronized (map) {
- return get(map).toArray(o);
- }
- }
- }
-
- /**
- * Sets implementation over the entries of the FastHashMap
- */
- private final class EntrySet extends AbstractCollectionView<Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {
-
- @Override
- protected Collection<Map.Entry<K, V>> get(final Map<K, V> map) {
- return map.entrySet();
- }
-
- @Override
- protected Map.Entry<K, V> iteratorNext(final Map.Entry<K, V> entry) {
- return entry;
- }
-
- }
-
- /**
- * Sets implementation over the keys of the FastHashMap
- */
- private final class KeySet extends AbstractCollectionView<K> implements Set<K> {
-
- @Override
- protected Collection<K> get(final Map<K, V> map) {
- return map.keySet();
- }
-
- @Override
- protected K iteratorNext(final Map.Entry<K, V> entry) {
- return entry.getKey();
- }
-
- }
-
- // Constructors
-
- /**
- * Collection implementation over the values of the FastHashMap
- */
- private final class Values extends AbstractCollectionView<V> {
-
- @Override
- protected Collection<V> get(final Map<K, V> map) {
- return map.values();
- }
-
- @Override
- protected V iteratorNext(final Map.Entry<K, V> entry) {
- return entry.getValue();
- }
- }
-
- private static final long serialVersionUID = 1L;
-
- /**
- * The underlying map we are managing.
- */
- private volatile Map<K, V> map;
-
- /**
- * Are we currently operating in "fast" mode?
- */
- private boolean fast;
-
- // Property access
-
- /**
- * Constructs an empty map.
- */
- public WeakFastHashMap() {
- this.map = createMap();
- }
-
-
-
- // Map access
-
- // These methods can forward straight to the wrapped Map in 'fast' mode.
- // (because they are query methods)
-
- /**
- * Constructs a new map with the same mappings as the specified map.
- *
- * @param map the map whose mappings are to be copied
- */
- public WeakFastHashMap(final Map<? extends K, ? extends V> map) {
- this.map = createMap(map);
- }
-
- /**
- * Remove all mappings from this map.
- */
- @Override
- public void clear() {
- if (fast) {
- synchronized (this) {
- map = createMap();
- }
- } else {
- synchronized (map) {
- map.clear();
- }
- }
- }
-
- /**
- * Gets a shallow copy of this {@code FastHashMap} instance. The keys and values themselves are not copied.
- *
- * @return a clone of this map
- */
- @Override
- public Object clone() {
- WeakFastHashMap<K, V> results = null;
- if (fast) {
- results = new WeakFastHashMap<>(map);
- } else {
- synchronized (map) {
- results = new WeakFastHashMap<>(map);
- }
- }
- results.setFast(getFast());
- return results;
- }
-
- protected Map<K, V> cloneMap(final Map<? extends K, ? extends V> map) {
- return createMap(map);
- }
-
- // Map modification
-
- // These methods perform special behavior in 'fast' mode.
- // The map is cloned, updated and then assigned back.
- // See the comments at the top as to why this won't always work.
-
- /**
- * Gets {@code true} if this map contains a mapping for the specified key.
- *
- * @param key the key to be searched for
- * @return true if the map contains the key
- */
- @Override
- public boolean containsKey(final Object key) {
- if (fast) {
- return map.containsKey(key);
- }
- synchronized (map) {
- return map.containsKey(key);
- }
- }
-
- /**
- * Gets {@code true} if this map contains one or more keys mapping to the specified value.
- *
- * @param value the value to be searched for
- * @return true if the map contains the value
- */
- @Override
- public boolean containsValue(final Object value) {
- if (fast) {
- return map.containsValue(value);
- }
- synchronized (map) {
- return map.containsValue(value);
- }
- }
-
- protected Map<K, V> createMap() {
- return new WeakHashMap<>();
- }
-
- protected Map<K, V> createMap(final int capacity) {
- return new WeakHashMap<>(capacity);
- }
-
- // Basic object methods
-
- protected Map<K, V> createMap(final int capacity, final float factor) {
- return new WeakHashMap<>(capacity, factor);
- }
-
- protected Map<K, V> createMap(final Map<? extends K, ? extends V> map) {
- return new WeakHashMap<>(map);
- }
-
- /**
- * Gets a collection view of the mappings contained in this map. Each element in the returned collection is a {@code Map.Entry}.
- *
- * @return the set of map Map entries
- */
- @Override
- public Set<Map.Entry<K, V>> entrySet() {
- return new EntrySet();
- }
-
- // Map views
-
- /**
- * Compare the specified object with this list for equality. This implementation uses exactly the code that is used to define the list equals function in
- * the documentation for the {@code Map.equals} method.
- *
- * @param o the object to be compared to this list
- * @return true if the two maps are equal
- */
- @Override
- public boolean equals(final Object o) {
- // Simple tests that require no synchronization
- if (o == this) {
- return true;
- }
- if (!(o instanceof Map)) {
- return false;
- }
- final Map<?, ?> mo = (Map<?, ?>) o;
-
- // Compare the two maps for equality
- if (fast) {
- if (mo.size() != map.size()) {
- return false;
- }
- for (final Map.Entry<K, V> e : map.entrySet()) {
- final K key = e.getKey();
- final V value = e.getValue();
- if (value == null) {
- if (!(mo.get(key) == null && mo.containsKey(key))) {
- return false;
- }
- } else if (!value.equals(mo.get(key))) {
- return false;
- }
- }
- return true;
-
- }
- synchronized (map) {
- if (mo.size() != map.size()) {
- return false;
- }
- for (final Map.Entry<K, V> e : map.entrySet()) {
- final K key = e.getKey();
- final V value = e.getValue();
- if (value == null) {
- if (!(mo.get(key) == null && mo.containsKey(key))) {
- return false;
- }
- } else if (!value.equals(mo.get(key))) {
- return false;
- }
- }
- return true;
- }
- }
-
- /**
- * Gets the value to which this map maps the specified key. Returns {@code null} if the map contains no mapping for this key, or if there is a mapping with
- * a value of {@code null}. Use the {@code containsKey()} method to disambiguate these cases.
- *
- * @param key the key whose value is to be returned
- * @return the value mapped to that key, or null
- */
- @Override
- public V get(final Object key) {
- if (fast) {
- return map.get(key);
- }
- synchronized (map) {
- return map.get(key);
- }
- }
-
- /**
- * Returns true if this map is operating in fast mode.
- *
- * @return true if this map is operating in fast mode
- */
- public boolean getFast() {
- return this.fast;
- }
-
- // Abstractions on Map creations (for subclasses such as WeakFastHashMap)
-
- /**
- * Gets the hash code value for this map. This implementation uses exactly the code that is used to define the list hash function in the documentation for
- * the {@code Map.hashCode} method.
- *
- * @return suitable integer hash code
- */
- @Override
- public int hashCode() {
- if (fast) {
- int h = 0;
- for (final Map.Entry<K, V> e : map.entrySet()) {
- h += e.hashCode();
- }
- return h;
- }
- synchronized (map) {
- int h = 0;
- for (final Map.Entry<K, V> e : map.entrySet()) {
- h += e.hashCode();
- }
- return h;
- }
- }
-
- /**
- * Gets {@code true} if this map contains no mappings.
- *
- * @return is the map currently empty
- */
- @Override
- public boolean isEmpty() {
- if (fast) {
- return map.isEmpty();
- }
- synchronized (map) {
- return map.isEmpty();
- }
- }
-
- /**
- * Gets a set view of the keys contained in this map.
- *
- * @return the set of the Map's keys
- */
- @Override
- public Set<K> keySet() {
- return new KeySet();
- }
-
- /**
- * Associate the specified value with the specified key in this map. If the map previously contained a mapping for this key, the old value is replaced and
- * returned.
- *
- * @param key the key with which the value is to be associated
- * @param value the value to be associated with this key
- * @return the value previously mapped to the key, or null
- */
- @Override
- public V put(final K key, final V value) {
- if (fast) {
- synchronized (this) {
- final Map<K, V> temp = cloneMap(map);
- final V result = temp.put(key, value);
- map = temp;
- return result;
- }
- }
- synchronized (map) {
- return map.put(key, value);
- }
- }
-
- /**
- * Copy all of the mappings from the specified map to this one, replacing any mappings with the same keys.
- *
- * @param in the map whose mappings are to be copied
- */
- @Override
- public void putAll(final Map<? extends K, ? extends V> in) {
- if (fast) {
- synchronized (this) {
- final Map<K, V> temp = cloneMap(map);
- temp.putAll(in);
- map = temp;
- }
- } else {
- synchronized (map) {
- map.putAll(in);
- }
- }
- }
-
- // Map view inner classes
-
- /**
- * Remove any mapping for this key, and return any previously mapped value.
- *
- * @param key the key whose mapping is to be removed
- * @return the value removed, or null
- */
- @Override
- public V remove(final Object key) {
- if (fast) {
- synchronized (this) {
- final Map<K, V> temp = cloneMap(map);
- final V result = temp.remove(key);
- map = temp;
- return result;
- }
- }
- synchronized (map) {
- return map.remove(key);
- }
- }
-
- /**
- * Sets whether this map is operating in fast mode.
- *
- * @param fast true if this map should operate in fast mode
- */
- public void setFast(final boolean fast) {
- this.fast = fast;
- }
-
- /**
- * Gets the number of key-value mappings in this map.
- *
- * @return the current size of the map
- */
- @Override
- public int size() {
- if (fast) {
- return map.size();
- }
- synchronized (map) {
- return map.size();
- }
- }
-
- /**
- * Gets a collection view of the values contained in this map.
- *
- * @return the set of the Map's values
- */
- @Override
- public Collection<V> values() {
- return new Values();
- }
-
-}
diff --git a/src/main/java/org/apache/commons/beanutils2/locale/LocaleConvertUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/locale/LocaleConvertUtilsBean.java
index 03600201..5f6ec9ad 100644
--- a/src/main/java/org/apache/commons/beanutils2/locale/LocaleConvertUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/locale/LocaleConvertUtilsBean.java
@@ -23,8 +23,8 @@ import java.math.BigInteger;
import java.util.Locale;
import java.util.Map;
+import org.apache.commons.beanutils2.BeanUtils;
import org.apache.commons.beanutils2.ConversionException;
-import org.apache.commons.beanutils2.WeakFastHashMap;
import org.apache.commons.beanutils2.locale.converters.BigDecimalLocaleConverter;
import org.apache.commons.beanutils2.locale.converters.BigIntegerLocaleConverter;
import org.apache.commons.beanutils2.locale.converters.ByteLocaleConverter;
@@ -106,15 +106,14 @@ public class LocaleConvertUtilsBean {
* <li>value = map of converters for the certain locale.</li>
* <ul>
*/
- private final WeakFastHashMap<Locale, Map<Class<?>, LocaleConverter<?>>> mapConverters;
+ private final Map<Locale, Map<Class<?>, LocaleConverter<?>>> mapConverters;
/**
* Makes the state by default (deregisters all converters for all locales) and then registers default locale converters.
*/
public LocaleConvertUtilsBean() {
- mapConverters = new WeakFastHashMap<>();
+ mapConverters = BeanUtils.createCache();
deregister();
- mapConverters.setFast(true);
}
/**
@@ -270,7 +269,7 @@ public class LocaleConvertUtilsBean {
* @return The map instance contains the all {@link LocaleConverter} types for the specified locale.
*/
protected Map<Class<?>, LocaleConverter<?>> create(final Locale locale) {
- final WeakFastHashMap<Class<?>, LocaleConverter<?>> converter = new WeakFastHashMap<>();
+ final Map<Class<?>, LocaleConverter<?>> converter = BeanUtils.createCache();
converter.put(BigDecimal.class, BigDecimalLocaleConverter.builder().setLocale(locale).setLocalizedPattern(applyLocalized).get());
converter.put(BigInteger.class, BigIntegerLocaleConverter.builder().setLocale(locale).setLocalizedPattern(applyLocalized).get());
@@ -301,8 +300,6 @@ public class LocaleConvertUtilsBean {
converter.put(java.sql.Time.class, SqlTimeLocaleConverter.builder().setLocale(locale).setPattern("HH:mm:ss").get());
converter.put(java.sql.Timestamp.class, SqlTimestampLocaleConverter.builder().setLocale(locale).setPattern("yyyy-MM-dd HH:mm:ss.S").get());
- converter.setFast(true);
-
return converter;
}
@@ -311,12 +308,8 @@ public class LocaleConvertUtilsBean {
*/
public void deregister() {
final Map<Class<?>, LocaleConverter<?>> defaultConverter = lookup(defaultLocale);
- mapConverters.setFast(false);
-
mapConverters.clear();
mapConverters.put(defaultLocale, defaultConverter);
-
- mapConverters.setFast(true);
}
/**
diff --git a/src/test/java/org/apache/commons/beanutils2/BeanMapTest.java b/src/test/java/org/apache/commons/beanutils2/BeanMapTest.java
index 97832432..9f80ebb9 100644
--- a/src/test/java/org/apache/commons/beanutils2/BeanMapTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/BeanMapTest.java
@@ -20,10 +20,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
+import java.util.function.Function;
import org.apache.commons.beanutils2.bugs.other.Jira87BeanFactory;
import org.apache.commons.collections4.map.AbstractMapTest;
@@ -31,7 +33,7 @@ import org.apache.commons.collections4.map.AbstractMapTest;
/**
* Tests {@link BeanMap}.
*/
-public class BeanMapTest extends AbstractMapTest<String, Object> {
+public class BeanMapTest extends AbstractMapTest<BeanMap, String, Object> {
public static class BeanThrowingExceptions extends BeanWithProperties {
@@ -150,7 +152,7 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
**/
private final Object objectInFullMap = new Object();
- /*
+ /**
* note to self. The getter and setter methods were generated by copying the field declarations and using the following regular expression search and
* replace:
*
@@ -158,9 +160,16 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
*
* Also note: The sample keys and mappings were generated manually.
*/
-
public BeanMapTest() {
- super("BeanMapTestCase");
+ }
+
+ @Override
+ protected Object computeIfAbsent(final String key, final Function<? super String, ? extends Object> mappingFunction) {
+ if (getMap().getBean() == null) {
+ // pretend this is a problem to make the test framework happy
+ throw new IllegalArgumentException();
+ }
+ return super.computeIfAbsent(key, mappingFunction);
}
@Override
@@ -196,7 +205,6 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
return values;
}
- @Override
public String[] ignoredTests() {
// Ignore the serialization tests on collection views.
return new String[] { "TestBeanMap.bulkTestMapEntrySet.testCanonicalEmptyCollectionExists",
@@ -226,7 +234,7 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
}
@Override
- public Map<String, Object> makeFullMap() {
+ public BeanMap makeFullMap() {
// note: These values must match (i.e. .equals() must return true)
// those returned from getSampleValues().
final BeanWithProperties bean = new BeanWithProperties();
@@ -244,10 +252,19 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
}
@Override
- public Map<String, Object> makeObject() {
+ public BeanMap makeObject() {
return new BeanMap();
}
+ @Override
+ protected Object putIfAbsent(final String key, final Object value) {
+ if (getMap().getBean() == null) {
+ // pretend this is a problem to make the test framework happy
+ throw new IllegalArgumentException();
+ }
+ return super.putIfAbsent(key, value);
+ }
+
public void testBeanMapClone() {
final BeanMap map = (BeanMap) makeFullMap();
try {
@@ -401,6 +418,12 @@ public class BeanMapTest extends AbstractMapTest<String, Object> {
assertEquals(method, map.getWriteMethod("someIntegerValue"));
}
+ @Override
+ public void testReplaceAll() {
+ assumeFalse(getMap().keySet().stream().anyMatch(k -> getMap().getWriteMethod(k) == null));
+ super.testReplaceAll();
+ }
+
/**
* Values is a dead copy in BeanMap, so refresh each time.
*/