Had this laying around...

- Added an IntegerIterable Transformer.
- Document that these *Iterable transformers work with List/Set/Collection...
  In case it wasn't clear.
- Added a sizeHint argument to the createCollectionBuilder method, take
  advantage of that in the IntegerIterable since we don't need to do any
  work to find the size.
This commit is contained in:
Ray Greenwell
2011-06-24 20:17:02 +00:00
parent d5eb7cf3ff
commit c26d9b29fb
@@ -23,6 +23,7 @@ import com.google.common.collect.Interners;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import com.samskivert.util.ByteEnum; import com.samskivert.util.ByteEnum;
import com.samskivert.util.ByteEnumUtil; import com.samskivert.util.ByteEnumUtil;
@@ -103,10 +104,10 @@ public class Transformers
} }
/** /**
* Combines the contents of an Iterable<String> column into a single String, terminating each * Combines the contents of a List/Set/Collection/Iterable<String> column into a single String,
* String element with a newline. A backslash ('\') in Strings will be prefixed by another * terminating each String element with a newline. Null-tolerant.
* backslash, newlines will be encoded as "\n", and null elements will be encoded as "\0" (but * A backslash ('\') in Strings will be prefixed by another backslash, newlines will be
* not terminated by a newline). * encoded as "\n", and null elements will be encoded as "\0" (but not terminated by a newline).
*/ */
public static class StringIterable extends StringBase<Iterable<String>> public static class StringIterable extends StringBase<Iterable<String>>
{ {
@@ -117,7 +118,7 @@ public class Transformers
@Override protected Builder<String, Iterable<String>> createBuilder (String encoded) @Override protected Builder<String, Iterable<String>> createBuilder (String encoded)
{ {
return createCollectionBuilder(_ftype, String.class, _immutable, _intern); return createCollectionBuilder(_ftype, String.class, _immutable, _intern, -1);
} }
} }
@@ -148,7 +149,7 @@ public class Transformers
{ {
// create a Builder for our field type // create a Builder for our field type
final Builder<E, Iterable<E>> ebuilder = createCollectionBuilder( final Builder<E, Iterable<E>> ebuilder = createCollectionBuilder(
_ftype, hasNullElement(encoded) ? null : _eclass, _immutable, _intern); _ftype, hasNullElement(encoded) ? null : _eclass, _immutable, _intern, -1);
// wrap that builder in one that accepts String elements // wrap that builder in one that accepts String elements
return new Builder<String, Iterable<E>>() { return new Builder<String, Iterable<E>>() {
public void add (String s) { public void add (String s) {
@@ -176,6 +177,56 @@ public class Transformers
protected Class<E> _eclass; protected Class<E> _eclass;
} }
/**
* Can transform a List/Set/Collection/Iterable to an int[] for storage in the db.
* Null-tolerant.
*/
public static class IntegerIterable extends Transformer<Iterable<Integer>, int[]>
{
@Override
public void init (Type fieldType, Transform annotation)
{
_ftype = fieldType;
_immutable = annotation.immutable();
_intern = annotation.intern();
}
@Override
public int[] toPersistent (Iterable<Integer> itr)
{
if (itr == null) {
return null;
}
Collection<Integer> coll = (itr instanceof Collection<?>)
? (Collection<Integer>)itr
: Lists.newArrayList(itr);
return Ints.toArray(coll);
}
@Override
public Iterable<Integer> fromPersistent (int[] value)
{
if (value == null) {
return null;
}
Builder<Integer, Iterable<Integer>> builder =
createCollectionBuilder(_ftype, Integer.class, _immutable, _intern, value.length);
for (int v : value) {
builder.add(v);
}
return builder.build();
}
/** The type of the field. */
protected Type _ftype;
/** Immutable hint. */
protected boolean _immutable;
/** Intern hint. */
protected boolean _intern;
}
/** /**
* An interface used by some of these transformers to build their result. * An interface used by some of these transformers to build their result.
*/ */
@@ -190,21 +241,27 @@ public class Transformers
* Create a builder that populates a collection. * Create a builder that populates a collection.
* *
* @param elementType if non-null and an enum, will be used to possibly create an EnumSet. * @param elementType if non-null and an enum, will be used to possibly create an EnumSet.
* @param sizeHint -1 or an *exact size* hint.
*/ */
protected static <E> Builder<E, Iterable<E>> createCollectionBuilder ( protected static <E> Builder<E, Iterable<E>> createCollectionBuilder (
Type fieldType, Class<E> elementType, boolean immutable, boolean intern) Type fieldType, Class<E> elementType, boolean immutable, boolean intern, int sizeHint)
{ {
Collection<E> adder; Collection<E> adder;
Collection<E> retval = null; Collection<E> retval = null;
Type clazz = (fieldType instanceof ParameterizedType) ? Type clazz = (fieldType instanceof ParameterizedType) ?
((ParameterizedType)fieldType).getRawType() : fieldType; ((ParameterizedType)fieldType).getRawType() : fieldType;
// TODO: fill out the collection types // TODO: fill out the collection types
// TODO: also, it might be nice to build into an ImmutableCollection if making
// immutable (instead of wrapping in a unmodifiableCollection), but that results in
// an extra copy... Perhaps we can add another flag that opts-in to that? Aiya.
if (clazz == HashSet.class || clazz == Set.class || clazz == EnumSet.class) { if (clazz == HashSet.class || clazz == Set.class || clazz == EnumSet.class) {
Set<E> set; Set<E> set;
if (clazz == HashSet.class || (elementType == null) || !elementType.isEnum()) { if (clazz == HashSet.class || (elementType == null) || !elementType.isEnum()) {
Preconditions.checkArgument(clazz != EnumSet.class, Preconditions.checkArgument(clazz != EnumSet.class,
"Cannot proceed: EnumSet field is to be populated with a null element."); "Cannot proceed: EnumSet field is to be populated with a null element.");
set = Sets.newHashSet(); set = (sizeHint < 0)
? Sets.<E>newHashSet()
: Sets.<E>newHashSetWithExpectedSize(sizeHint);
} else { } else {
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
Class<Enum> eclazz = (Class<Enum>)elementType; Class<Enum> eclazz = (Class<Enum>)elementType;
@@ -221,7 +278,9 @@ public class Transformers
adder = Lists.newLinkedList(); adder = Lists.newLinkedList();
} else { } else {
List<E> list = Lists.newArrayList(); List<E> list = (sizeHint < 0)
? Lists.<E>newArrayList()
: Lists.<E>newArrayListWithCapacity(sizeHint);
adder = list; adder = list;
if (immutable && if (immutable &&
((clazz == List.class) || ((clazz == List.class) ||