001    /*
002     * Copyright (C) 2008 The Guava Authors
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.base;
018    
019    import static com.google.common.base.Preconditions.checkNotNull;
020    
021    import com.google.common.annotations.Beta;
022    import com.google.common.annotations.GwtCompatible;
023    
024    import java.io.IOException;
025    import java.util.AbstractList;
026    import java.util.Arrays;
027    import java.util.Iterator;
028    import java.util.Map;
029    import java.util.Map.Entry;
030    
031    import javax.annotation.CheckReturnValue;
032    import javax.annotation.Nullable;
033    
034    /**
035     * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a
036     * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns
037     * them as a {@link String}. Example: <pre>   {@code
038     *
039     *   Joiner joiner = Joiner.on("; ").skipNulls();
040     *    . . .
041     *   return joiner.join("Harry", null, "Ron", "Hermione");}</pre>
042     *
043     * This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are
044     * converted to strings using {@link Object#toString()} before being appended.
045     *
046     * <p>If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining
047     * methods will throw {@link NullPointerException} if any given element is null.
048     *
049     * <p><b>Warning: joiner instances are always immutable</b>; a configuration method such as {@code
050     * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner
051     * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code
052     * static final} constants. <pre>   {@code
053     *
054     *   // Bad! Do not do this!
055     *   Joiner joiner = Joiner.on(',');
056     *   joiner.skipNulls(); // does nothing!
057     *   return joiner.join("wrong", null, "wrong");}</pre>
058     *
059     * @author Kevin Bourrillion
060     * @since 2.0 (imported from Google Collections Library)
061     */
062    @GwtCompatible
063    public class Joiner {
064      /**
065       * Returns a joiner which automatically places {@code separator} between consecutive elements.
066       */
067      public static Joiner on(String separator) {
068        return new Joiner(separator);
069      }
070    
071      /**
072       * Returns a joiner which automatically places {@code separator} between consecutive elements.
073       */
074      public static Joiner on(char separator) {
075        return new Joiner(String.valueOf(separator));
076      }
077    
078      private final String separator;
079    
080      private Joiner(String separator) {
081        this.separator = checkNotNull(separator);
082      }
083    
084      private Joiner(Joiner prototype) {
085        this.separator = prototype.separator;
086      }
087    
088      /**
089       * <b>Deprecated.</b>
090       *
091       * @since 11.0
092       * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code parts} to
093       *     {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
094       *     {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
095       */
096      @Beta
097      @Deprecated
098      public final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A
099          appendTo(A appendable, I parts) throws IOException {
100        return appendTo(appendable, (Iterator<?>) parts);
101      }
102    
103      /**
104       * Appends the string representation of each of {@code parts}, using the previously configured
105       * separator between each, to {@code appendable}.
106       */
107      public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException {
108        return appendTo(appendable, parts.iterator());
109      }
110    
111      /**
112       * Appends the string representation of each of {@code parts}, using the previously configured
113       * separator between each, to {@code appendable}.
114       *
115       * @since 11.0
116       */
117      @Beta
118      public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
119        checkNotNull(appendable);
120        if (parts.hasNext()) {
121          appendable.append(toString(parts.next()));
122          while (parts.hasNext()) {
123            appendable.append(separator);
124            appendable.append(toString(parts.next()));
125          }
126        }
127        return appendable;
128      }
129    
130      /**
131       * Appends the string representation of each of {@code parts}, using the previously configured
132       * separator between each, to {@code appendable}.
133       */
134      public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException {
135        return appendTo(appendable, Arrays.asList(parts));
136      }
137    
138      /**
139       * Appends to {@code appendable} the string representation of each of the remaining arguments.
140       */
141      public final <A extends Appendable> A appendTo(
142          A appendable, @Nullable Object first, @Nullable Object second, Object... rest)
143              throws IOException {
144        return appendTo(appendable, iterable(first, second, rest));
145      }
146    
147      /**
148       * <b>Deprecated.</b>
149       *
150       * @since 11.0
151       * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code parts} to
152       *     {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
153       *     {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
154       */
155      @Beta
156      @Deprecated
157      public final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder
158          appendTo(StringBuilder builder, I parts) {
159        return appendTo(builder, (Iterator<?>) parts);
160      }
161    
162      /**
163       * Appends the string representation of each of {@code parts}, using the previously configured
164       * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
165       * Iterable)}, except that it does not throw {@link IOException}.
166       */
167      public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
168        return appendTo(builder, parts.iterator());
169      }
170    
171      /**
172       * Appends the string representation of each of {@code parts}, using the previously configured
173       * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
174       * Iterable)}, except that it does not throw {@link IOException}.
175       *
176       * @since 11.0
177       */
178      @Beta
179      public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
180        try {
181          appendTo((Appendable) builder, parts);
182        } catch (IOException impossible) {
183          throw new AssertionError(impossible);
184        }
185        return builder;
186      }
187    
188      /**
189       * Appends the string representation of each of {@code parts}, using the previously configured
190       * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
191       * Iterable)}, except that it does not throw {@link IOException}.
192       */
193      public final StringBuilder appendTo(StringBuilder builder, Object[] parts) {
194        return appendTo(builder, Arrays.asList(parts));
195      }
196    
197      /**
198       * Appends to {@code builder} the string representation of each of the remaining arguments.
199       * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
200       * throw {@link IOException}.
201       */
202      public final StringBuilder appendTo(
203          StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) {
204        return appendTo(builder, iterable(first, second, rest));
205      }
206    
207      /**
208       * <b>Deprecated.</b>
209       *
210       * @since 11.0
211       * @deprecated use {@link #join(Iterator)} by casting {@code parts} to
212       *     {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
213       *     {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
214       */
215      @Beta
216      @Deprecated
217      public final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) {
218        return join((Iterator<?>) parts);
219      }
220    
221      /**
222       * Returns a string containing the string representation of each of {@code parts}, using the
223       * previously configured separator between each.
224       */
225      public final String join(Iterable<?> parts) {
226        return join(parts.iterator());
227      }
228    
229      /**
230       * Returns a string containing the string representation of each of {@code parts}, using the
231       * previously configured separator between each.
232       *
233       * @since 11.0
234       */
235      @Beta
236      public final String join(Iterator<?> parts) {
237        return appendTo(new StringBuilder(), parts).toString();
238      }
239    
240      /**
241       * Returns a string containing the string representation of each of {@code parts}, using the
242       * previously configured separator between each.
243       */
244      public final String join(Object[] parts) {
245        return join(Arrays.asList(parts));
246      }
247    
248      /**
249       * Returns a string containing the string representation of each argument, using the previously
250       * configured separator between each.
251       */
252      public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
253        return join(iterable(first, second, rest));
254      }
255    
256      /**
257       * Returns a joiner with the same behavior as this one, except automatically substituting {@code
258       * nullText} for any provided null elements.
259       */
260      @CheckReturnValue
261      public Joiner useForNull(final String nullText) {
262        checkNotNull(nullText);
263        return new Joiner(this) {
264          @Override CharSequence toString(Object part) {
265            return (part == null) ? nullText : Joiner.this.toString(part);
266          }
267    
268          @Override public Joiner useForNull(String nullText) {
269            checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
270            throw new UnsupportedOperationException("already specified useForNull");
271          }
272    
273          @Override public Joiner skipNulls() {
274            throw new UnsupportedOperationException("already specified useForNull");
275          }
276        };
277      }
278    
279      /**
280       * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
281       * provided null elements.
282       */
283      @CheckReturnValue
284      public Joiner skipNulls() {
285        return new Joiner(this) {
286          @Override public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
287              throws IOException {
288            checkNotNull(appendable, "appendable");
289            checkNotNull(parts, "parts");
290            while (parts.hasNext()) {
291              Object part = parts.next();
292              if (part != null) {
293                appendable.append(Joiner.this.toString(part));
294                break;
295              }
296            }
297            while (parts.hasNext()) {
298              Object part = parts.next();
299              if (part != null) {
300                appendable.append(separator);
301                appendable.append(Joiner.this.toString(part));
302              }
303            }
304            return appendable;
305          }
306    
307          @Override public Joiner useForNull(String nullText) {
308            checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
309            throw new UnsupportedOperationException("already specified skipNulls");
310          }
311    
312          @Override public MapJoiner withKeyValueSeparator(String kvs) {
313            checkNotNull(kvs); // weird: just to satisfy NullPointerTester.
314            throw new UnsupportedOperationException("can't use .skipNulls() with maps");
315          }
316        };
317      }
318    
319      /**
320       * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
321       * this {@code Joiner} otherwise.
322       */
323      @CheckReturnValue
324      public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
325        return new MapJoiner(this, keyValueSeparator);
326      }
327    
328      /**
329       * An object that joins map entries in the same manner as {@code Joiner} joins iterables and
330       * arrays. Like {@code Joiner}, it is thread-safe and immutable.
331       *
332       * <p>In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code
333       * Multimap} entries in two distinct modes:
334       *
335       * <ul>
336       * <li>To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a
337       *     {@code MapJoiner} method that accepts entries as input, and receive output of the form
338       *     {@code key1=A&key1=B&key2=C}.
339       * <li>To output a single entry for each key, pass {@code multimap.asMap()} to a {@code MapJoiner}
340       *     method that accepts a map as input, and receive output of the form {@code
341       *     key1=[A, B]&key2=C}.
342       * </ul>
343       *
344       * @since 2.0 (imported from Google Collections Library)
345       */
346      public final static class MapJoiner {
347        private final Joiner joiner;
348        private final String keyValueSeparator;
349    
350        private MapJoiner(Joiner joiner, String keyValueSeparator) {
351          this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull
352          this.keyValueSeparator = checkNotNull(keyValueSeparator);
353        }
354    
355        /**
356         * Appends the string representation of each entry of {@code map}, using the previously
357         * configured separator and key-value separator, to {@code appendable}.
358         */
359        public <A extends Appendable> A appendTo(A appendable, Map<?, ?> map) throws IOException {
360          return appendTo(appendable, map.entrySet());
361        }
362    
363        /**
364         * Appends the string representation of each entry of {@code map}, using the previously
365         * configured separator and key-value separator, to {@code builder}. Identical to {@link
366         * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}.
367         */
368        public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) {
369          return appendTo(builder, map.entrySet());
370        }
371    
372        /**
373         * Returns a string containing the string representation of each entry of {@code map}, using the
374         * previously configured separator and key-value separator.
375         */
376        public String join(Map<?, ?> map) {
377          return join(map.entrySet());
378        }
379    
380        /**
381         * <b>Deprecated.</b>
382         *
383         * @since 11.0
384         * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code entries} to
385         *     {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
386         *     {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
387         *     in June 2013.</b>
388         */
389        @Beta
390        @Deprecated
391        public <A extends Appendable,
392            I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
393            A appendTo(A appendable, I entries) throws IOException {
394          Iterator<? extends Entry<?, ?>> iterator = entries;
395          return appendTo(appendable, iterator);
396        }
397    
398        /**
399         * Appends the string representation of each entry in {@code entries}, using the previously
400         * configured separator and key-value separator, to {@code appendable}.
401         *
402         * @since 10.0
403         */
404        @Beta
405        public <A extends Appendable> A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries)
406            throws IOException {
407          return appendTo(appendable, entries.iterator());
408        }
409    
410        /**
411         * Appends the string representation of each entry in {@code entries}, using the previously
412         * configured separator and key-value separator, to {@code appendable}.
413         *
414         * @since 11.0
415         */
416        @Beta
417        public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
418            throws IOException {
419          checkNotNull(appendable);
420          if (parts.hasNext()) {
421            Entry<?, ?> entry = parts.next();
422            appendable.append(joiner.toString(entry.getKey()));
423            appendable.append(keyValueSeparator);
424            appendable.append(joiner.toString(entry.getValue()));
425            while (parts.hasNext()) {
426              appendable.append(joiner.separator);
427              Entry<?, ?> e = parts.next();
428              appendable.append(joiner.toString(e.getKey()));
429              appendable.append(keyValueSeparator);
430              appendable.append(joiner.toString(e.getValue()));
431            }
432          }
433          return appendable;
434        }
435    
436        /**
437         * <b>Deprecated.</b>
438         *
439         * @since 11.0
440         * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code entries} to
441         *     {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
442         *     {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
443         *     in June 2013.</b>
444         */
445        @Beta
446        @Deprecated
447        public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
448            StringBuilder appendTo(StringBuilder builder, I entries) throws IOException {
449          Iterator<? extends Entry<?, ?>> iterator = entries;
450          return appendTo(builder, iterator);
451        }
452    
453        /**
454         * Appends the string representation of each entry in {@code entries}, using the previously
455         * configured separator and key-value separator, to {@code builder}. Identical to {@link
456         * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
457         *
458         * @since 10.0
459         */
460        @Beta
461        public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) {
462          return appendTo(builder, entries.iterator());
463        }
464    
465        /**
466         * Appends the string representation of each entry in {@code entries}, using the previously
467         * configured separator and key-value separator, to {@code builder}. Identical to {@link
468         * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
469         *
470         * @since 11.0
471         */
472        @Beta
473        public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {
474          try {
475            appendTo((Appendable) builder, entries);
476          } catch (IOException impossible) {
477            throw new AssertionError(impossible);
478          }
479          return builder;
480        }
481    
482        /**
483         * <b>Deprecated.</b>
484         *
485         * @since 11.0
486         * @deprecated use {@link #join(Iterator)} by casting {@code entries} to
487         *     {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
488         *     {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
489         *     in June 2013.</b>
490         */
491        @Beta
492        @Deprecated
493        public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
494            String join(I entries) throws IOException {
495          Iterator<? extends Entry<?, ?>> iterator = entries;
496          return join(iterator);
497        }
498    
499        /**
500         * Returns a string containing the string representation of each entry in {@code entries}, using
501         * the previously configured separator and key-value separator.
502         *
503         * @since 10.0
504         */
505        @Beta
506        public String join(Iterable<? extends Entry<?, ?>> entries) {
507          return join(entries.iterator());
508        }
509    
510        /**
511         * Returns a string containing the string representation of each entry in {@code entries}, using
512         * the previously configured separator and key-value separator.
513         *
514         * @since 11.0
515         */
516        @Beta
517        public String join(Iterator<? extends Entry<?, ?>> entries) {
518          return appendTo(new StringBuilder(), entries).toString();
519        }
520    
521        /**
522         * Returns a map joiner with the same behavior as this one, except automatically substituting
523         * {@code nullText} for any provided null keys or values.
524         */
525        @CheckReturnValue
526        public MapJoiner useForNull(String nullText) {
527          return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator);
528        }
529      }
530    
531      CharSequence toString(Object part) {
532        checkNotNull(part);  // checkNotNull for GWT (do not optimize).
533        return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
534      }
535    
536      private static Iterable<Object> iterable(
537          final Object first, final Object second, final Object[] rest) {
538        checkNotNull(rest);
539        return new AbstractList<Object>() {
540          @Override public int size() {
541            return rest.length + 2;
542          }
543    
544          @Override public Object get(int index) {
545            switch (index) {
546              case 0:
547                return first;
548              case 1:
549                return second;
550              default:
551                return rest[index - 2];
552            }
553          }
554        };
555      }
556    }