Skip to content

Instantly share code, notes, and snippets.

@agentgt
Created July 12, 2012 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agentgt/3101471 to your computer and use it in GitHub Desktop.
Save agentgt/3101471 to your computer and use it in GitHub Desktop.
An appendable decorator that will soften the IOException, handle nulls, and do collection joins.
package com.snaphop.util;
import javax.annotation.Nullable;
public class AppendableDecorator {
protected final CharSequence nullText;
protected final CharSequence newLine;
protected final boolean skipNull;
protected final CharSequence prefix;
protected final CharSequence suffix;
protected final CharSequence separator;
protected AppendableDecorator(
@Nullable
CharSequence nullText,
@Nullable
CharSequence newLine,
@Nullable
CharSequence separator,
boolean skipNull,
@Nullable
CharSequence prefix,
@Nullable
CharSequence suffix) {
super();
this.nullText = nullText;
if (newLine == null)
this.newLine = getSystemProperty("line.separator");
else
this.newLine = newLine;
this.prefix = prefix == null ? "" : prefix;
this.suffix = suffix == null ? "" : suffix;
this.separator = separator == null ? "" : separator;
this.skipNull = skipNull;
}
private AppendableDecorator() {
this(null, null, null, false, null, null);
}
public static AppendableDecorator builder() {
return new AppendableDecorator();
}
private static AppendableDecorator defaultDecorator = new AppendableDecorator();
public static <O extends Appendable> BetterAppendable<O> decorate(O wrappedAppendable) {
return defaultDecorator.wrap(wrappedAppendable);
}
//If your using eclipse a nice diagonal black pattern of the parameter being replaced should be visible.
public <O extends Appendable> BetterAppendable<O> wrap(O wrappedAppendable) {
return new BetterAppendable<O>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator nullText(CharSequence nullText) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator newLine(CharSequence newLine) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator separator(CharSequence separator) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator skipNull(boolean skipNull) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator prefix(CharSequence prefix) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public AppendableDecorator suffix(CharSequence suffix) {
return new AppendableDecorator(nullText, newLine, separator, skipNull, prefix, suffix);
}
public final String join(Object [] o) {
return wrap(new StringBuilder()).appendParts(o).toString();
}
protected static String getSystemProperty(String property) {
try {
return System.getProperty(property);
} catch (SecurityException ex) {
// we are not allowed to look at this property
System.err.println("Caught a SecurityException reading the system property '" + property
+ "'; the SystemUtils property value will default to null.");
return null;
}
}
}
package com.snaphop.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Iterator;
import javax.annotation.Nullable;
public class BetterAppendable<A extends Appendable> extends AppendableDecorator implements Appendable {
private final A wrappedAppendable;
public BetterAppendable(
A wrappedAppendable,
@Nullable
CharSequence nullText,
@Nullable
CharSequence newLine,
@Nullable
CharSequence separator,
boolean skipNull,
@Nullable
CharSequence prefix,
@Nullable
CharSequence suffix) {
super(nullText, newLine, separator, skipNull, prefix, suffix);
this.wrappedAppendable = checkNotNull(wrappedAppendable);
}
public BetterAppendable(A wrappedAppendable, CharSequence nullText) {
this(wrappedAppendable, nullText, null, null, false, null, null);
}
public BetterAppendable(A wrappedAppendable) {
this(wrappedAppendable, null);
}
public BetterAppendable(BetterAppendable<A> p) {
this(p.wrappedAppendable, p.nullText, p.newLine, p.separator, p.skipNull, p.prefix, p.suffix);
}
//If your using eclipse a nice diagonal black pattern of the parameter being replaced should be visible.
public BetterAppendable<A> nullText(CharSequence nullText) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public BetterAppendable<A> newLine(CharSequence newLine) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public BetterAppendable<A> separator(CharSequence separator) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public BetterAppendable<A> skipNull(boolean skipNull) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public BetterAppendable<A> prefix(CharSequence prefix) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
public BetterAppendable<A> suffix(CharSequence suffix) {
return new BetterAppendable<A>(wrappedAppendable, nullText, newLine, separator, skipNull, prefix, suffix);
}
@Override
public BetterAppendable<A> append(CharSequence cs) {
try {
return rewrap(wrappedAppendable.append(cs));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public BetterAppendable<A> append(char c) {
try {
return rewrap(wrappedAppendable.append(c));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public BetterAppendable<A> append(CharSequence cs, int start, int end) {
try {
return rewrap(wrappedAppendable.append(cs, start, end));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public BetterAppendable<A> append(Object obj) {
if (obj == null) {
return appendNull();
}
return append(obj.toString());
}
public BetterAppendable<A> appendParts(Iterator<?> parts) {
BetterAppendable<A> a = this;
// Lets decide if we are skipping nulls or not
if (! skipNull ) {
if (parts.hasNext()) {
if (prefix != null) a = a.append(prefix);
a = a.append(objectToString(parts.next()));
if (suffix != null) a = a.append(suffix);
while (parts.hasNext()) {
a = a.append(separator);
if (prefix != null) a = a.append(prefix);
a = a.append(objectToString(parts.next()));
if (suffix != null) a = a.append(suffix);
}
}
}
else {
while (parts.hasNext()) {
Object part = parts.next();
if (part != null) {
if (prefix != null) a = a.append(prefix);
a = a.append(objectToString(part));
if (suffix != null) a = a.append(suffix);
break;
}
}
while (parts.hasNext()) {
Object part = parts.next();
if (part != null) {
a = a.append(separator);
if (prefix != null)
a = a.append(prefix);
a = a.append(objectToString(part));
if (suffix != null)
a = a.append(suffix);
}
}
}
return a;
}
public final BetterAppendable<A> appendParts(Object[] parts) {
return appendParts(Arrays.asList(parts));
}
public final BetterAppendable<A> appendParts(@Nullable Object first, @Nullable Object second,
Object... rest) {
return appendParts(iterable(first, second, rest));
}
public BetterAppendable<A> appendParts(Iterable<?> parts) {
return appendParts(parts.iterator());
}
public BetterAppendable<A> appendNull() {
if (nullText == null) {
return this;
}
return append(nullText);
}
public BetterAppendable<A> appendLine() {
if (newLine == null) {
return this;
}
return append(newLine);
}
public BetterAppendable<A> padStart(CharSequence string, int minLength, char padChar) {
checkNotNull(string); // eager for GWT.
if (string.length() >= minLength) {
return this;
}
BetterAppendable<A> a = this;
for (int i = string.length(); i < minLength; i++) {
a = a.append(padChar);
}
a = a.append(string);
return a;
}
public BetterAppendable<A> padEnd(CharSequence string, int minLength, char padChar) {
checkNotNull(string); // eager for GWT.
if (string.length() >= minLength) {
return this;
}
BetterAppendable<A> a = this;
a = a.append(string);
for (int i = string.length(); i < minLength; i++) {
a = a.append(padChar);
}
return a;
}
public BetterAppendable<A> repeat(Object string, long count) {
if (count <= 1) {
checkArgument(count >= 0, "invalid count: %s", count);
return (count == 0) ? this.append("") : this;
}
BetterAppendable<A> a = this;
for (long i = 0; i < count; count++) {
a = a.append(objectToString(string));
}
return a;
}
@SuppressWarnings("unchecked")
private BetterAppendable<A> rewrap(Appendable a) {
if (a != wrappedAppendable) {
// Oh you naughty bastard this is going to hurt.
return wrap((A) a);
}
return this;
}
public A getAppendable() {
return wrappedAppendable;
}
public String toString() {
return wrappedAppendable.toString();
}
CharSequence objectToString(Object part) {
if (part == null) {
return checkNotNull(nullText, "null passed nullText not set"); // checkNotNull for GWT (do not optimize).
}
else {
return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
}
}
private static Iterable<Object> iterable(final Object first, final Object second, final Object[] rest) {
checkNotNull(rest);
return new AbstractList<Object>() {
@Override
public int size() {
return rest.length + 2;
}
@Override
public Object get(int index) {
switch (index) {
case 0:
return first;
case 1:
return second;
default:
return rest[index - 2];
}
}
};
}
}
package com.snaphop.util;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
public class BetterAppendableTest {
AppendableDecorator appendableDecorator =
AppendableDecorator.builder()
.separator(",")
.suffix("'")
.prefix("'")
.nullText("hmm cookies...");
@Before
public void setUp() throws Exception {}
@Test
public void testAppend() {
String results = new BetterAppendable<Appendable>(new StringBuilder()).append("stuff").toString();
assertEquals("stuff", results);
}
@Test
public void testSeparator() {
String results = AppendableDecorator.decorate(new StringBuilder())
.separator(",").suffix("'").prefix("'")
.append("Hello there lets count to 5")
.appendLine()
.nullText("hmm cookies...")
.appendParts(1,2,3, null)
.toString(); // can also do .getAppendable().getBuffer().toString()
assertEquals("Hello there lets count to 5\n" +
"'1','2','3','hmm cookies...'", results);
results = appendableDecorator.wrap(new StringBuilder())
.append("Hello there lets count to 5")
.appendLine()
.appendParts(1,2,3, null)
.toString(); // can also do .getAppendable().getBuffer().toString()
assertEquals("Hello there lets count to 5\n" +
"'1','2','3','hmm cookies...'", results);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment