001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.collections;
014
015import static java.util.Collections.*;
016
017import java.util.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.json.*;
021import org.apache.juneau.serializer.*;
022
023/**
024 * A fluent {@link LinkedHashMap}.
025 *
026 * <p>
027 * Provides various convenience methods for creating and populating a map with minimal code.
028 *
029 * <h5 class='figure'>Examples:</h5>
030 * <p class='bcode w800'>
031 *    <jc>// A map of string key/value pairs.</jc>
032 *    AMap&lt;String,String&gt; m = AMap.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>);
033 *
034 *    <jc>// Append to map.</jc>
035 *    m.a(<js>"baz"</js>, <js>"qux"</js>);
036 *
037 *    <jc>// Create an unmodifiable view of this list.</jc>
038 *    Map&lt;String,String&gt; m2 = m.unmodifiable();
039 *
040 *    <jc>// Convert to simplified JSON.</jc>
041 *    String json = m.asString();
042 *
043 *    <jc>// Convert to XML.</jc>
044 *    String json = m.asString(XmlSerializer.<jsf>DEFAULT</jsm>);
045 * </p>
046 *
047 * @param <K> The key type.
048 * @param <V> The value type.
049 */
050public final class AMap<K,V> extends LinkedHashMap<K,V> {
051
052   private static final long serialVersionUID = 1L;
053
054   //------------------------------------------------------------------------------------------------------------------
055   // Constructors.
056   //------------------------------------------------------------------------------------------------------------------
057
058   /**
059    * Constructor.
060    */
061   public AMap() {}
062
063   /**
064    * Copy constructor.
065    *
066    * @param copy The map to copy.  Can be <jk>null</jk>.
067    */
068   public AMap(Map<K,V> copy) {
069      super(copy == null ? emptyMap() : copy);
070   }
071
072   //------------------------------------------------------------------------------------------------------------------
073   // Creators.
074   //------------------------------------------------------------------------------------------------------------------
075
076   /**
077    * Creates an empty map.
078    *
079    * @return A new empty map.
080    */
081   public static <K,V> AMap<K,V> of() {
082      return new AMap<>();
083   }
084
085   /**
086    * Creates a map with one entry.
087    *
088    * @param key Entry key.
089    * @param value Entry value.
090    * @return A new map with one entry.
091    */
092   public static <K,V> AMap<K,V> of(K key, V value) {
093      return new AMap<K,V>().a(key, value);
094   }
095
096   /**
097    * Creates a map out of a list of key/value pairs.
098    *
099    * @param <K> The key type.
100    * @param <V> The value type.
101    * @param parameters
102    *    The parameters.
103    *    <br>Must be an even number of parameters.
104    *    <br>It's up to you to ensure that the parameters are the correct type.
105    * @return A new map.
106    */
107   @SuppressWarnings("unchecked")
108   public static <K,V> AMap<K,V> ofPairs(Object...parameters) {
109      AMap<K,V> m = AMap.of();
110      if (parameters.length % 2 != 0)
111         throw new BasicRuntimeException("Odd number of parameters passed into AMap.ofPairs()");
112      for (int i = 0; i < parameters.length; i+=2)
113         m.put((K)parameters[i], (V)parameters[i+1]);
114      return m;
115   }
116
117
118   @SuppressWarnings("javadoc")
119   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2) {
120      return AMap.of(k1,v1).a(k2,v2);
121   }
122
123   @SuppressWarnings("javadoc")
124   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
125      return AMap.of(k1,v1).a(k2,v2).a(k3,v3);
126   }
127
128   @SuppressWarnings("javadoc")
129   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
130      return AMap.of(k1,v1).a(k2,v2).a(k3,v3).a(k4,v4);
131   }
132
133   @SuppressWarnings("javadoc")
134   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
135      return AMap.of(k1,v1).a(k2,v2).a(k3,v3).a(k4,v4).a(k5,v5);
136   }
137
138   @SuppressWarnings("javadoc")
139   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
140      return AMap.of(k1,v1).a(k2,v2).a(k3,v3).a(k4,v4).a(k5,v5).a(k6,v6);
141   }
142
143   @SuppressWarnings("javadoc")
144   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
145      return AMap.of(k1,v1).a(k2,v2).a(k3,v3).a(k4,v4).a(k5,v5).a(k6,v6).a(k7,v7);
146   }
147
148   @SuppressWarnings("javadoc")
149   public static <K,V> AMap<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
150      return AMap.of(k1,v1).a(k2,v2).a(k3,v3).a(k4,v4).a(k5,v5).a(k6,v6).a(k7,v7).a(k8,v8);
151   }
152
153   /**
154    * Creates a new map initialized with the specified contents.
155    *
156    * @param copy Initialize with these contents.  Can be <jk>null</jk>.
157    * @return A new map.  Never <jk>null</jk>.
158    */
159   public static <K,V> AMap<K,V> of(Map<K,V> copy) {
160      return new AMap<>(copy);
161   }
162
163   /**
164    * Creates an unmodifiable copy of the specified map.
165    *
166    * @param copy The map to copy.
167    * @return A new unmodifiable map, never <jk>null</jk>.
168    */
169   public static <K,V> Map<K,V> unmodifiable(Map<K,V> copy) {
170      if (copy == null || copy.isEmpty())
171         return emptyMap();
172      return new AMap<>(copy).unmodifiable();
173   }
174
175   /**
176    * Creates a copy of the collection if it's not <jk>null</jk>.
177    *
178    * @param c The initial values.
179    * @return A new list, or <jk>null</jk> if the collection is <jk>null</jk>.
180    */
181   public static <K,V> AMap<K,V> nullable(Map<K,V> c) {
182      return c == null ? null : of(c);
183   }
184
185   //------------------------------------------------------------------------------------------------------------------
186   // Appenders.
187   //------------------------------------------------------------------------------------------------------------------
188
189   /**
190    * Add.
191    *
192    * <p>
193    * Adds an entry to this map.
194    *
195    * @param k The key.
196    * @param v The value.
197    * @return This object (for method chaining).
198    */
199   public AMap<K,V> a(K k, V v) {
200      put(k, v);
201      return this;
202   }
203
204   /**
205    * Add all.
206    *
207    * <p>
208    * Appends all the entries in the specified map to this map.
209    *
210    * @param c The map to copy.
211    * @return This object (for method chaining).
212    */
213   public AMap<K,V> aa(Map<K,V> c) {
214      super.putAll(c);
215      return this;
216   }
217
218   //------------------------------------------------------------------------------------------------------------------
219   // Other methods.
220   //------------------------------------------------------------------------------------------------------------------
221
222   /**
223    * Returns an unmodifiable view of this map.
224    *
225    * @return An unmodifiable view of this map.
226    */
227   public Map<K,V> unmodifiable() {
228      return this.isEmpty() ? emptyMap() : unmodifiableMap(this);
229   }
230
231   /**
232    * Convert to a string using the specified serializer.
233    *
234    * @param ws The serializer to use to serialize this collection.
235    * @return This collection serialized to a string.
236    */
237   public String asString(WriterSerializer ws) {
238      return ws.toString(this);
239   }
240
241   /**
242    * Convert to Simplified JSON.
243    *
244    * @return This collection serialized to a string.
245    */
246   public String asString() {
247      return SimpleJsonSerializer.DEFAULT.toString(this);
248   }
249
250   /**
251    * Convert to Simplified JSON.
252    */
253   @Override /* Object */
254   public String toString() {
255      return asString(SimpleJsonSerializer.DEFAULT);
256   }
257}