Better String[] Transformer, RFC.
This commit is contained in:
@@ -20,8 +20,24 @@
|
|||||||
|
|
||||||
package com.samskivert.depot;
|
package com.samskivert.depot;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.samskivert.depot.annotation.Column;
|
import com.samskivert.depot.annotation.Column;
|
||||||
|
|
||||||
|
//import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains various generally useful {@link Transformer} implementations. To use a transformer, you
|
* Contains various generally useful {@link Transformer} implementations. To use a transformer, you
|
||||||
* specify it via a {@link Column} annotation. For example:
|
* specify it via a {@link Column} annotation. For example:
|
||||||
@@ -57,4 +73,109 @@ public class Transformers
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@Beta
|
||||||
|
public static class StringArray implements Transformer<String[], String>
|
||||||
|
{
|
||||||
|
public String toPersistent (String[] value)
|
||||||
|
{
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return StringIterable.toPersistent0(Arrays.asList(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] fromPersistent (Class<?> ftype, String encoded)
|
||||||
|
{
|
||||||
|
if (encoded == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Iterables.toArray(StringIterable.fromPersistent0(encoded), String.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Beta
|
||||||
|
public static class StringIterable implements Transformer<Iterable<String>, String>
|
||||||
|
{
|
||||||
|
public String toPersistent (Iterable<String> value)
|
||||||
|
{
|
||||||
|
return toPersistent0(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<String> fromPersistent (Class<?> ftype, String encoded)
|
||||||
|
{
|
||||||
|
ArrayList<String> value = fromPersistent0(encoded);
|
||||||
|
if (value == null ||
|
||||||
|
ftype == ArrayList.class || ftype == List.class || ftype == Collection.class ||
|
||||||
|
ftype == Iterable.class) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (ftype == LinkedList.class) {
|
||||||
|
return Lists.newLinkedList(value);
|
||||||
|
}
|
||||||
|
if (ftype == HashSet.class || ftype == Set.class) {
|
||||||
|
return Sets.newHashSet(value);
|
||||||
|
}
|
||||||
|
// else: reflection? See if it's a collection, call the 0-arg constructor, add all
|
||||||
|
// and return? Something?
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String toPersistent0 (Iterable<String> value)
|
||||||
|
{
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (String s : value) {
|
||||||
|
if (s == null) {
|
||||||
|
buf.append('\uFFFC');
|
||||||
|
} else {
|
||||||
|
s = s.replace("\\", "\\\\"); // turn \ into \\
|
||||||
|
s = s.replace("\n", "\\n"); // turn newline into \n
|
||||||
|
s = s.replace("\uFFFC", "\\\uFFFC"); // preslash the nullmarker too
|
||||||
|
buf.append(s).append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ArrayList<String> fromPersistent0 (String encoded)
|
||||||
|
{
|
||||||
|
if (encoded == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<String> value = Lists.newArrayList();
|
||||||
|
StringBuilder buf = new StringBuilder(encoded.length());
|
||||||
|
for (int ii = 0, nn = encoded.length(); ii < nn; ii++) {
|
||||||
|
char c = encoded.charAt(ii);
|
||||||
|
switch (c) {
|
||||||
|
case '\uFFFC':
|
||||||
|
Preconditions.checkArgument(buf.length() == 0, "Invalid encoded string");
|
||||||
|
value.add(null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
value.add(buf.toString()); // TODO: intern?
|
||||||
|
buf.setLength(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
try {
|
||||||
|
buf.append(encoded.charAt(++ii)); // take the next char at face value
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid encoded string", e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buf.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make sure there are no left-over characters
|
||||||
|
Preconditions.checkArgument(buf.length() == 0, "Invalid encoded string");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user