diff --git a/src/main/java/org/apache/commons/collections4/MapBuilder.java b/src/main/java/org/apache/commons/collections4/MapBuilder.java new file mode 100644 index 0000000000..539ec3c617 --- /dev/null +++ b/src/main/java/org/apache/commons/collections4/MapBuilder.java @@ -0,0 +1,133 @@ +/* + * 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.collections4; + +import org.apache.commons.collections4.map.HashedMap; + +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.Collections; + +/** + * Defines an Helper Builder that generates a {@code Map} + * A Builder class to help decide which type of map to use based on simple requirements. + * Currently It takes care of only basic types of Maps and can be extended to different types of Maps available in the ecosystem. + * + *
{@code
+ * Map builderMap = new MapBuilder().setIterationOrder(MapBuilder.KeyOrder.INSERTION_ORDER).build();
+ * builderMap.put("A", 1);
+ * builderMap.put("X", 24);
+ * builderMap.put("B", 2);
+ * builderMap.put("Y", 26);
+ * }
+ * + */ +public class MapBuilder { + + private Comparator comparator; + private KeyOrder iterationOrder; + private boolean synchronizedMap; + private boolean immutable; + private Map data; + + public MapBuilder() { + comparator = null; + iterationOrder = KeyOrder.UNORDERED; + synchronizedMap = false; + immutable = false; + data = null; + } + + /* + Sets the comparator to be used to decide the Iteration order in case of iterationOrder = COMPARATOR_ORDER; + */ + public MapBuilder setComparator(Comparator comparator) { + this.comparator = comparator; + return this; + } + + /* + Sets the Iteration order to be used from [UNORDERED, NATURAL_ORDER, INSERTION_ORDER, COMPARATOR_ORDER] + */ + public MapBuilder setIterationOrder(KeyOrder iterationOrder) { + this.iterationOrder = iterationOrder; + return this; + } + + /* + Since most of the maps are not inherently thread safe , this option provides the option if the map has to be synchronised or not + */ + public MapBuilder setSynchronizedMap(boolean synchronizedMap) { + this.synchronizedMap = synchronizedMap; + return this; + } + + /* + Option to create a immutable map from the provided data + */ + public MapBuilder setImmutable(boolean immutable) { + this.immutable = immutable; + return this; + } + + /* + Populates the Map with some preexisting data. All the selected conditions will be automatically applied to the existing data + */ + public MapBuilder setData(Map data) { + this.data = data; + return this; + } + + /* + Builder Method which takes care of all the conditions and returns the required Map. + */ + public Map build() { + Map map; + switch (iterationOrder) { + case NATURAL_ORDER : + case COMPARATOR_ORDER: + map = new TreeMap(comparator); + break; + case INSERTION_ORDER : + map = new LinkedHashMap(); + break; + default: + map = new HashedMap(); + break; + } + + if (MapUtils.isNotEmpty(data)) { + map.putAll(data); + } + + if (synchronizedMap) { + map = Collections.synchronizedMap(map); + } + + if (immutable) { + map = Collections.unmodifiableMap(map); + } + + return map; + } + + enum KeyOrder { + UNORDERED, NATURAL_ORDER, INSERTION_ORDER, COMPARATOR_ORDER; + } +} diff --git a/src/test/java/org/apache/commons/collections4/MapBuilderTest.java b/src/test/java/org/apache/commons/collections4/MapBuilderTest.java new file mode 100644 index 0000000000..3fcdb3980c --- /dev/null +++ b/src/test/java/org/apache/commons/collections4/MapBuilderTest.java @@ -0,0 +1,124 @@ +/* + * 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.collections4; + +import org.apache.commons.collections4.map.HashedMap; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.LinkedHashMap; +import java.util.TreeMap; + +/** + * Test Cases for Map Builder + */ +public class MapBuilderTest { + + @Test + void setComparator() { + // Null Comparator + Map myMap = new HashMap(); + myMap.put("A", 1); + myMap.put("X", 24); + myMap.put("B", 2); + myMap.put("Y", 26); + + // Reverse comparator + Map builderMap = new MapBuilder().setData(myMap).setIterationOrder(MapBuilder.KeyOrder.COMPARATOR_ORDER).setComparator(Comparator.reverseOrder()).build(); + Assert.assertEquals(builderMap.keySet().stream().findFirst().get(), "Y"); + Assert.assertEquals(builderMap.keySet().stream().skip(1).findFirst().get(), "X"); + Assert.assertEquals(builderMap.keySet().stream().skip(2).findFirst().get(), "B"); + Assert.assertEquals(builderMap.keySet().stream().skip(3).findFirst().get(), "A"); + } + + @Test + void setIterationOrder() { + //Key Order = UNORDERED + Map myMap = new HashMap(); + myMap.put("A", 1); + myMap.put("X", 24); + myMap.put("B", 2); + myMap.put("Y", 26); + Map builderMap = new MapBuilder().setData(myMap).setIterationOrder(MapBuilder.KeyOrder.UNORDERED).build(); + Assert.assertTrue(builderMap instanceof HashedMap); + + //Key Order = INSERTION ORDER + builderMap = new MapBuilder().setIterationOrder(MapBuilder.KeyOrder.INSERTION_ORDER).build(); + builderMap.put("A", 1); + builderMap.put("X", 24); + builderMap.put("B", 2); + builderMap.put("Y", 26); + Assert.assertTrue(builderMap instanceof LinkedHashMap); + + //Key Order = NATURAL ORDER + builderMap = new MapBuilder().setIterationOrder(MapBuilder.KeyOrder.NATURAL_ORDER).build(); + builderMap.put("A", 1); + builderMap.put("X", 24); + builderMap.put("B", 2); + builderMap.put("Y", 26); + Assert.assertTrue(builderMap instanceof TreeMap); + + //Key Order = COMPARATOR ORDER and null comparator + builderMap = new MapBuilder().setIterationOrder(MapBuilder.KeyOrder.COMPARATOR_ORDER).build(); + builderMap.put("A", 1); + builderMap.put("X", 24); + builderMap.put("B", 2); + builderMap.put("Y", 26); + Assert.assertTrue(builderMap instanceof TreeMap); + + //Key Order = COMPARATOR ORDER and valid comparator + builderMap = new MapBuilder().setIterationOrder(MapBuilder.KeyOrder.COMPARATOR_ORDER).setComparator(Comparator.reverseOrder()).build(); + builderMap.put("A", 1); + builderMap.put("X", 24); + builderMap.put("B", 2); + builderMap.put("Y", 26); + Assert.assertTrue(builderMap instanceof TreeMap); + } + + @Test + void setImmutable() { + Map myMap = new HashMap(); + myMap.put("A", 1); + myMap.put("B", 2); + Map builderMap = new MapBuilder().setData(myMap).setImmutable(true).build(); + boolean exceptionThrown = false; + try { + builderMap.put("C", 3); + }catch (UnsupportedOperationException e) { + exceptionThrown = true; + } + Assert.assertTrue(exceptionThrown); + } + + @Test + void setData() { + Map myMap = new HashMap(); + myMap.put("A", 1); + myMap.put("B", 2); + Map builderMap = new MapBuilder().setData(myMap).build(); + Assert.assertEquals(myMap, builderMap); + } + + @Test + void build() { + Map builderMap = new MapBuilder().build(); + Assert.assertTrue(builderMap.size() == 0); + } +}