package com.supaham.commons;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
public class Joiner {
private com.google.common.base.Joiner joiner;
/**
* Returns a joiner which automatically places {@code separator} between consecutive elements.
*/
public static Joiner on(String separator) {
return new Joiner(separator);
}
/**
* Returns a joiner which automatically places {@code separator} between consecutive elements.
*/
public static Joiner on(char separator) {
return new Joiner(String.valueOf(separator));
}
private Joiner(String separator) {
this.joiner = com.google.common.base.Joiner.on(separator);
}
private Joiner(Joiner prototype) {
this.joiner = prototype.joiner;
}
private Joiner(com.google.common.base.Joiner prototype) {
this.joiner = prototype;
}
/**
* Returns a {@link FunctionJoiner} with the same behaviour as this Joiner, and the given
* function. The function is used to transform input when calling {@code join} methods.
*
* @param function function
* @param <T> type of input to transform
*
* @return new function joiner
*/
public <T> FunctionJoiner<T> function(Function<T, String> function) {
return new FunctionJoiner<>(this, function);
}
// TODO add functionality for limiting join output.
/* ================================
* >> DELEGATE METHODS
* ================================ */
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code appendable}.
*/
public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException {
return joiner.appendTo(appendable, parts);
}
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code appendable}.
*/
public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
return joiner.appendTo(appendable, parts);
}
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code appendable}.
*/
public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException {
return joiner.appendTo(appendable, Arrays.asList(parts));
}
/**
* Appends to {@code appendable} the string representation of each of the remaining arguments.
*/
public final <A extends Appendable> A appendTo(A appendable,
@Nullable Object first,
@Nullable Object second,
Object... rest) throws IOException {
return joiner.appendTo(appendable, first, second, rest);
}
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
* Iterable)}, except that it does not throw {@link IOException}.
*/
public StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
return joiner.appendTo(builder, parts);
}
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
* Iterable)}, except that it does not throw {@link IOException}.
*/
public StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
return joiner.appendTo(builder, parts);
}
/**
* Appends the string representation of each of {@code parts}, using the previously configured
* separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
* Iterable)}, except that it does not throw {@link IOException}.
*/
public StringBuilder appendTo(StringBuilder builder, Object[] parts) {
return joiner.appendTo(builder, parts);
}
/**
* Appends to {@code builder} the string representation of each of the remaining arguments.
* Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
* throw {@link IOException}.
*/
public StringBuilder appendTo(StringBuilder builder, @Nullable Object first,
@Nullable Object second, Object... rest) {
return joiner.appendTo(builder, first, second, rest);
}
/**
* Returns a string containing the string representation of each of {@code parts}, using the
* previously configured separator between each.
*/
public String join(Iterable<?> parts) {
return joiner.join(parts);
}
/**
* Returns a string containing the string representation of each of {@code parts}, using the
* previously configured separator between each.
*/
public String join(Iterator<?> parts) {
return joiner.join(parts);
}
/**
* Returns a string containing the string representation of each of {@code parts}, using the
* previously configured separator between each.
*/
public String join(Object[] parts) {
return joiner.join(parts);
}
/**
* Returns a string containing the string representation of each argument, using the previously
* configured separator between each.
*/
public String join(@Nullable Object first, @Nullable Object second, Object... rest) {
return joiner.join(first, second, rest);
}
/**
* Returns a joiner with the same behavior as this one, except automatically substituting {@code
* nullText} for any provided null elements.
*/
@CheckReturnValue public Joiner useForNull(String nullText) {
return new Joiner(joiner.useForNull(nullText));
}
/**
* Returns a joiner with the same behavior as this joiner, except automatically skipping over any
* provided null elements.
*/
@CheckReturnValue public Joiner skipNulls() {
return new Joiner(joiner.skipNulls());
}
/* ================================
* >> /DELEGATE METHODS
* ================================ */
public final class FunctionJoiner<T> extends Joiner {
private final Function<T, String> function;
private FunctionJoiner(Joiner joiner, Function<T, String> function) {
super(joiner);
this.function = function;
}
@Override public String join(Iterable<?> parts) {
return joiner.join(Iterables.transform((Iterable<T>) parts, this.function));
}
@Override public String join(Iterator<?> parts) {
return joiner.join(Iterators.transform((Iterator<T>) parts, this.function));
}
@Override public String join(Object[] parts) {
return join(Arrays.asList(parts));
}
@Override public String join(@Nullable Object first, @Nullable Object second, Object... rest) {
return join(Arrays.asList(first, second, rest));
}
@Override public FunctionJoiner<T> useForNull(String nullText) {
return new FunctionJoiner<>(super.useForNull(nullText), this.function);
}
@Override public FunctionJoiner<T> skipNulls() {
return new FunctionJoiner<>(super.skipNulls(), this.function);
}
}
}