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