package com.googlecode.objectify.impl.load; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.AbstractList; import java.util.Arrays; import java.util.Collection; import com.googlecode.objectify.impl.TypeUtils; /** * <p>This setter handles an embedded array by constructing the array and all the objects * inside. It expects the value to be a collection type so it "fans out" the values to * all the embedded objects in the array, calling the next setter in the chain with each * value.</p> */ public class EmbeddedArraySetter extends EmbeddedMultivalueSetter { Class<?> componentType; Constructor<?> componentTypeCtor; /** * The lame Arrays.asList() wrapper doesn't support the clear() operation, and * we need to be able to set the size back to 0 for our newly crated array of * nulls. This wrapper uses the array as a backing store but it doesn't start * out thinking the collection is populated. */ static class EmptyArrayListWrapper extends AbstractList<Object> { int size; Object[] array; public EmptyArrayListWrapper(Object[] array) { this.array = array; } @Override public Object get(int index) { return this.array[index]; } @Override public int size() { return this.size; } @Override public boolean add(Object element) { this.array[this.size++] = element; return true; } } /** */ public EmbeddedArraySetter(Field field, String path, Collection<String> collisionPaths) { super(field, path, collisionPaths); assert field.getType().isArray(); this.componentType = this.field.getType().getComponentType(); this.componentTypeCtor = TypeUtils.getNoArgConstructor(this.componentType); } /* (non-Javadoc) * @see com.googlecode.objectify.impl.load.EmbeddedMultivalueSetter#getComponentConstructor() */ @Override protected Constructor<?> getComponentConstructor() { return this.componentTypeCtor; } /* (non-Javadoc) * @see com.googlecode.objectify.impl.load.EmbeddedMultivalueSetter#getOrCreateCollection(java.lang.Object, int) */ @Override protected Collection<Object> getOrCreateCollection(Object onPojo, int size) { // First we need the actual array of child objects Object embeddedArray = this.field.get(onPojo); if (embeddedArray == null) { // Make the array and set it on the pojo field embeddedArray = Array.newInstance(this.componentType, size); this.field.set(onPojo, embeddedArray); return new EmptyArrayListWrapper((Object[])embeddedArray); } else { return Arrays.asList((Object[])embeddedArray); } } }