arrow-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jacq...@apache.org
Subject [07/17] arrow git commit: ARROW-1: Initial Arrow Code Commit
Date Wed, 17 Feb 2016 12:39:42 GMT
http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/HolderReaderImpl.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/HolderReaderImpl.java b/java/vector/src/main/codegen/templates/HolderReaderImpl.java
new file mode 100644
index 0000000..3005fca
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/HolderReaderImpl.java
@@ -0,0 +1,290 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<@pp.dropOutputFile />
+<#list vv.types as type>
+<#list type.minor as minor>
+<#list ["", "Nullable", "Repeated"] as holderMode>
+<#assign nullMode = holderMode />
+<#if holderMode == "Repeated"><#assign nullMode = "Nullable" /></#if>
+
+<#assign lowerName = minor.class?uncap_first />
+<#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
+<#assign name = minor.class?cap_first />
+<#assign javaType = (minor.javaType!type.javaType) />
+<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#assign safeType=friendlyType />
+<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
+<#assign fields = minor.fields!type.fields />
+
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/${holderMode}${name}HolderReaderImpl.java" />
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.joda.time.Period;
+
+// Source code generated using FreeMarker template ${.template_name}
+
+@SuppressWarnings("unused")
+public class ${holderMode}${name}HolderReaderImpl extends AbstractFieldReader {
+
+  private ${nullMode}${name}Holder holder;
+<#if holderMode == "Repeated" >
+  private int index = -1;
+  private ${holderMode}${name}Holder repeatedHolder;
+</#if>
+
+  public ${holderMode}${name}HolderReaderImpl(${holderMode}${name}Holder holder) {
+<#if holderMode == "Repeated" >
+    this.holder = new ${nullMode}${name}Holder();
+    this.repeatedHolder = holder;
+<#else>
+    this.holder = holder;
+</#if>
+  }
+
+  @Override
+  public int size() {
+<#if holderMode == "Repeated">
+    return repeatedHolder.end - repeatedHolder.start;
+<#else>
+    throw new UnsupportedOperationException("You can't call size on a Holder value reader.");
+</#if>
+  }
+
+  @Override
+  public boolean next() {
+<#if holderMode == "Repeated">
+    if(index + 1 < repeatedHolder.end) {
+      index++;
+      repeatedHolder.vector.getAccessor().get(repeatedHolder.start + index, holder);
+      return true;
+    } else {
+      return false;
+    }
+<#else>
+    throw new UnsupportedOperationException("You can't call next on a single value reader.");
+</#if>
+
+  }
+
+  @Override
+  public void setPosition(int index) {
+    throw new UnsupportedOperationException("You can't call next on a single value reader.");
+  }
+
+  @Override
+  public MajorType getType() {
+<#if holderMode == "Repeated">
+    return this.repeatedHolder.TYPE;
+<#else>
+    return this.holder.TYPE;
+</#if>
+  }
+
+  @Override
+  public boolean isSet() {
+    <#if holderMode == "Repeated">
+    return this.repeatedHolder.end!=this.repeatedHolder.start;
+    <#elseif nullMode == "Nullable">
+    return this.holder.isSet == 1;
+    <#else>
+    return true;
+    </#if>
+    
+  }
+
+<#if holderMode != "Repeated">
+@Override
+  public void read(${name}Holder h) {
+  <#list fields as field>
+    h.${field.name} = holder.${field.name};
+  </#list>
+  }
+
+  @Override
+  public void read(Nullable${name}Holder h) {
+  <#list fields as field>
+    h.${field.name} = holder.${field.name};
+  </#list>
+    h.isSet = isSet() ? 1 : 0;
+  }
+</#if>
+
+<#if holderMode == "Repeated">
+  @Override
+  public ${friendlyType} read${safeType}(int index){
+    repeatedHolder.vector.getAccessor().get(repeatedHolder.start + index, holder);
+    ${friendlyType} value = read${safeType}();
+    if (this.index > -1) {
+      repeatedHolder.vector.getAccessor().get(repeatedHolder.start + this.index, holder);
+    }
+    return value;
+  }
+</#if>
+
+  @Override
+  public ${friendlyType} read${safeType}(){
+<#if nullMode == "Nullable">
+    if (!isSet()) {
+      return null;
+    }
+</#if>
+
+<#if type.major == "VarLen">
+
+      int length = holder.end - holder.start;
+      byte[] value = new byte [length];
+      holder.buffer.getBytes(holder.start, value, 0, length);
+
+<#if minor.class == "VarBinary">
+      return value;
+<#elseif minor.class == "Var16Char">
+      return new String(value);
+<#elseif minor.class == "VarChar">
+      Text text = new Text();
+      text.set(value);
+      return text;
+</#if>
+
+<#elseif minor.class == "Interval">
+      Period p = new Period();
+      return p.plusMonths(holder.months).plusDays(holder.days).plusMillis(holder.milliseconds);
+
+<#elseif minor.class == "IntervalDay">
+      Period p = new Period();
+      return p.plusDays(holder.days).plusMillis(holder.milliseconds);
+
+<#elseif minor.class == "Decimal9" ||
+         minor.class == "Decimal18" >
+      BigInteger value = BigInteger.valueOf(holder.value);
+      return new BigDecimal(value, holder.scale);
+
+<#elseif minor.class == "Decimal28Dense" ||
+         minor.class == "Decimal38Dense">
+      return org.apache.arrow.vector.util.DecimalUtility.getBigDecimalFromDense(holder.buffer,
+                                                                                holder.start,
+                                                                                holder.nDecimalDigits,
+                                                                                holder.scale,
+                                                                                holder.maxPrecision,
+                                                                                holder.WIDTH);
+
+<#elseif minor.class == "Decimal28Sparse" ||
+         minor.class == "Decimal38Sparse">
+      return org.apache.arrow.vector.util.DecimalUtility.getBigDecimalFromSparse(holder.buffer,
+                                                                                 holder.start,
+                                                                                 holder.nDecimalDigits,
+                                                                                 holder.scale);
+
+<#elseif minor.class == "Bit" >
+      return new Boolean(holder.value != 0);
+<#else>
+      ${friendlyType} value = new ${friendlyType}(this.holder.value);
+      return value;
+</#if>
+
+  }
+
+  @Override
+  public Object readObject() {
+<#if holderMode == "Repeated" >
+    List<Object> valList = Lists.newArrayList();
+    for (int i = repeatedHolder.start; i < repeatedHolder.end; i++) {
+      valList.add(repeatedHolder.vector.getAccessor().getObject(i));
+    }
+    return valList;
+<#else>
+    return readSingleObject();
+</#if>
+  }
+
+  private Object readSingleObject() {
+<#if nullMode == "Nullable">
+    if (!isSet()) {
+      return null;
+    }
+</#if>
+
+<#if type.major == "VarLen">
+      int length = holder.end - holder.start;
+      byte[] value = new byte [length];
+      holder.buffer.getBytes(holder.start, value, 0, length);
+
+<#if minor.class == "VarBinary">
+      return value;
+<#elseif minor.class == "Var16Char">
+      return new String(value);
+<#elseif minor.class == "VarChar">
+      Text text = new Text();
+      text.set(value);
+      return text;
+</#if>
+
+<#elseif minor.class == "Interval">
+      Period p = new Period();
+      return p.plusMonths(holder.months).plusDays(holder.days).plusMillis(holder.milliseconds);
+
+<#elseif minor.class == "IntervalDay">
+      Period p = new Period();
+      return p.plusDays(holder.days).plusMillis(holder.milliseconds);
+
+<#elseif minor.class == "Decimal9" ||
+         minor.class == "Decimal18" >
+      BigInteger value = BigInteger.valueOf(holder.value);
+      return new BigDecimal(value, holder.scale);
+
+<#elseif minor.class == "Decimal28Dense" ||
+         minor.class == "Decimal38Dense">
+      return org.apache.arrow.vector.util.DecimalUtility.getBigDecimalFromDense(holder.buffer,
+                                                                                holder.start,
+                                                                                holder.nDecimalDigits,
+                                                                                holder.scale,
+                                                                                holder.maxPrecision,
+                                                                                holder.WIDTH);
+
+<#elseif minor.class == "Decimal28Sparse" ||
+         minor.class == "Decimal38Sparse">
+      return org.apache.arrow.vector.util.DecimalUtility.getBigDecimalFromSparse(holder.buffer,
+                                                                                 holder.start,
+                                                                                 holder.nDecimalDigits,
+                                                                                 holder.scale);
+
+<#elseif minor.class == "Bit" >
+      return new Boolean(holder.value != 0);
+<#else>
+      ${friendlyType} value = new ${friendlyType}(this.holder.value);
+      return value;
+</#if>
+  }
+
+<#if holderMode != "Repeated" && nullMode != "Nullable">
+  public void copyAsValue(${minor.class?cap_first}Writer writer){
+    writer.write(holder);
+  }
+</#if>
+}
+
+</#list>
+</#list>
+</#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/ListWriters.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/ListWriters.java b/java/vector/src/main/codegen/templates/ListWriters.java
new file mode 100644
index 0000000..cf9fa30
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/ListWriters.java
@@ -0,0 +1,234 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<@pp.dropOutputFile />
+
+<#list ["Single", "Repeated"] as mode>
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/${mode}ListWriter.java" />
+
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+<#if mode == "Single">
+  <#assign containerClass = "AbstractContainerVector" />
+  <#assign index = "idx()">
+<#else>
+  <#assign containerClass = "RepeatedListVector" />
+  <#assign index = "currentChildIndex">
+</#if>
+
+
+<#include "/@includes/vv_imports.ftl" />
+
+/*
+ * This class is generated using FreeMarker and the ${.template_name} template.
+ */
+@SuppressWarnings("unused")
+public class ${mode}ListWriter extends AbstractFieldWriter {
+  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${mode}ListWriter.class);
+
+  static enum Mode { INIT, IN_MAP, IN_LIST <#list vv.types as type><#list type.minor as minor>, IN_${minor.class?upper_case}</#list></#list> }
+
+  private final String name;
+  protected final ${containerClass} container;
+  private Mode mode = Mode.INIT;
+  private FieldWriter writer;
+  protected RepeatedValueVector innerVector;
+
+  <#if mode == "Repeated">private int currentChildIndex = 0;</#if>
+  public ${mode}ListWriter(String name, ${containerClass} container, FieldWriter parent){
+    super(parent);
+    this.name = name;
+    this.container = container;
+  }
+
+  public ${mode}ListWriter(${containerClass} container, FieldWriter parent){
+    super(parent);
+    this.name = null;
+    this.container = container;
+  }
+
+  @Override
+  public void allocate() {
+    if(writer != null) {
+      writer.allocate();
+    }
+
+    <#if mode == "Repeated">
+    container.allocateNew();
+    </#if>
+  }
+
+  @Override
+  public void clear() {
+    if (writer != null) {
+      writer.clear();
+    }
+  }
+
+  @Override
+  public void close() {
+    clear();
+    container.close();
+    if (innerVector != null) {
+      innerVector.close();
+    }
+  }
+
+  @Override
+  public int getValueCapacity() {
+    return innerVector == null ? 0 : innerVector.getValueCapacity();
+  }
+
+  public void setValueCount(int count){
+    if(innerVector != null) innerVector.getMutator().setValueCount(count);
+  }
+
+  @Override
+  public MapWriter map() {
+    switch(mode) {
+    case INIT:
+      int vectorCount = container.size();
+      final RepeatedMapVector vector = container.addOrGet(name, RepeatedMapVector.TYPE, RepeatedMapVector.class);
+      innerVector = vector;
+      writer = new RepeatedMapWriter(vector, this);
+      if(vectorCount != container.size()) {
+        writer.allocate();
+      }
+      writer.setPosition(${index});
+      mode = Mode.IN_MAP;
+      return writer;
+    case IN_MAP:
+      return writer;
+    }
+
+    throw new RuntimeException(getUnsupportedErrorMsg("MAP", mode.name()));
+
+  }
+
+  @Override
+  public ListWriter list() {
+    switch(mode) {
+    case INIT:
+      final int vectorCount = container.size();
+      final RepeatedListVector vector = container.addOrGet(name, RepeatedListVector.TYPE, RepeatedListVector.class);
+      innerVector = vector;
+      writer = new RepeatedListWriter(null, vector, this);
+      if(vectorCount != container.size()) {
+        writer.allocate();
+      }
+      writer.setPosition(${index});
+      mode = Mode.IN_LIST;
+      return writer;
+    case IN_LIST:
+      return writer;
+    }
+
+    throw new RuntimeException(getUnsupportedErrorMsg("LIST", mode.name()));
+
+  }
+
+  <#list vv.types as type><#list type.minor as minor>
+  <#assign lowerName = minor.class?uncap_first />
+  <#assign upperName = minor.class?upper_case />
+  <#assign capName = minor.class?cap_first />
+  <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
+
+  private static final MajorType ${upperName}_TYPE = Types.repeated(MinorType.${upperName});
+
+  @Override
+  public ${capName}Writer ${lowerName}() {
+    switch(mode) {
+    case INIT:
+      final int vectorCount = container.size();
+      final Repeated${capName}Vector vector = container.addOrGet(name, ${upperName}_TYPE, Repeated${capName}Vector.class);
+      innerVector = vector;
+      writer = new Repeated${capName}WriterImpl(vector, this);
+      if(vectorCount != container.size()) {
+        writer.allocate();
+      }
+      writer.setPosition(${index});
+      mode = Mode.IN_${upperName};
+      return writer;
+    case IN_${upperName}:
+      return writer;
+    }
+
+    throw new RuntimeException(getUnsupportedErrorMsg("${upperName}", mode.name()));
+
+  }
+  </#list></#list>
+
+  public MaterializedField getField() {
+    return container.getField();
+  }
+
+  <#if mode == "Repeated">
+
+  public void startList() {
+    final RepeatedListVector list = (RepeatedListVector) container;
+    final RepeatedListVector.RepeatedMutator mutator = list.getMutator();
+
+    // make sure that the current vector can support the end position of this list.
+    if(container.getValueCapacity() <= idx()) {
+      mutator.setValueCount(idx()+1);
+    }
+
+    // update the repeated vector to state that there is current+1 objects.
+    final RepeatedListHolder h = new RepeatedListHolder();
+    list.getAccessor().get(idx(), h);
+    if (h.start >= h.end) {
+      mutator.startNewValue(idx());
+    }
+    currentChildIndex = container.getMutator().add(idx());
+    if(writer != null) {
+      writer.setPosition(currentChildIndex);
+    }
+  }
+
+  public void endList() {
+    // noop, we initialize state at start rather than end.
+  }
+  <#else>
+
+  public void setPosition(int index) {
+    super.setPosition(index);
+    if(writer != null) {
+      writer.setPosition(index);
+    }
+  }
+
+  public void startList() {
+    // noop
+  }
+
+  public void endList() {
+    // noop
+  }
+  </#if>
+
+  private String getUnsupportedErrorMsg(String expected, String found) {
+    final String f = found.substring(3);
+    return String.format("In a list of type %s, encountered a value of type %s. "+
+      "Drill does not support lists of different types.",
+       f, expected
+    );
+  }
+}
+</#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/MapWriters.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/MapWriters.java b/java/vector/src/main/codegen/templates/MapWriters.java
new file mode 100644
index 0000000..7001367
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/MapWriters.java
@@ -0,0 +1,240 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<@pp.dropOutputFile />
+<#list ["Single", "Repeated"] as mode>
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/${mode}MapWriter.java" />
+<#if mode == "Single">
+<#assign containerClass = "MapVector" />
+<#assign index = "idx()">
+<#else>
+<#assign containerClass = "RepeatedMapVector" />
+<#assign index = "currentChildIndex">
+</#if>
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+import java.util.Map;
+
+import org.apache.arrow.vector.holders.RepeatedMapHolder;
+import org.apache.arrow.vector.AllocationHelper;
+import org.apache.arrow.vector.complex.reader.FieldReader;
+import org.apache.arrow.vector.complex.writer.FieldWriter;
+
+import com.google.common.collect.Maps;
+
+/*
+ * This class is generated using FreeMarker and the ${.template_name} template.
+ */
+@SuppressWarnings("unused")
+public class ${mode}MapWriter extends AbstractFieldWriter {
+
+  protected final ${containerClass} container;
+  private final Map<String, FieldWriter> fields = Maps.newHashMap();
+  <#if mode == "Repeated">private int currentChildIndex = 0;</#if>
+
+  private final boolean unionEnabled;
+
+  public ${mode}MapWriter(${containerClass} container, FieldWriter parent, boolean unionEnabled) {
+    super(parent);
+    this.container = container;
+    this.unionEnabled = unionEnabled;
+  }
+
+  public ${mode}MapWriter(${containerClass} container, FieldWriter parent) {
+    this(container, parent, false);
+  }
+
+  @Override
+  public int getValueCapacity() {
+    return container.getValueCapacity();
+  }
+
+  @Override
+  public boolean isEmptyMap() {
+    return 0 == container.size();
+  }
+
+  @Override
+  public MaterializedField getField() {
+      return container.getField();
+  }
+
+  @Override
+  public MapWriter map(String name) {
+      FieldWriter writer = fields.get(name.toLowerCase());
+    if(writer == null){
+      int vectorCount=container.size();
+        MapVector vector = container.addOrGet(name, MapVector.TYPE, MapVector.class);
+      if(!unionEnabled){
+        writer = new SingleMapWriter(vector, this);
+      } else {
+        writer = new PromotableWriter(vector, container);
+      }
+      if(vectorCount != container.size()) {
+        writer.allocate();
+      }
+      writer.setPosition(${index});
+      fields.put(name.toLowerCase(), writer);
+    }
+    return writer;
+  }
+
+  @Override
+  public void close() throws Exception {
+    clear();
+    container.close();
+  }
+
+  @Override
+  public void allocate() {
+    container.allocateNew();
+    for(final FieldWriter w : fields.values()) {
+      w.allocate();
+    }
+  }
+
+  @Override
+  public void clear() {
+    container.clear();
+    for(final FieldWriter w : fields.values()) {
+      w.clear();
+    }
+  }
+
+  @Override
+  public ListWriter list(String name) {
+    FieldWriter writer = fields.get(name.toLowerCase());
+    int vectorCount = container.size();
+    if(writer == null) {
+      if (!unionEnabled){
+        writer = new SingleListWriter(name,container,this);
+      } else{
+        writer = new PromotableWriter(container.addOrGet(name, Types.optional(MinorType.LIST), ListVector.class), container);
+      }
+      if (container.size() > vectorCount) {
+        writer.allocate();
+      }
+      writer.setPosition(${index});
+      fields.put(name.toLowerCase(), writer);
+    }
+    return writer;
+  }
+
+  <#if mode == "Repeated">
+  public void start() {
+      // update the repeated vector to state that there is current+1 objects.
+    final RepeatedMapHolder h = new RepeatedMapHolder();
+    final RepeatedMapVector map = (RepeatedMapVector) container;
+    final RepeatedMapVector.Mutator mutator = map.getMutator();
+
+    // Make sure that the current vector can support the end position of this list.
+    if(container.getValueCapacity() <= idx()) {
+      mutator.setValueCount(idx()+1);
+    }
+
+    map.getAccessor().get(idx(), h);
+    if (h.start >= h.end) {
+      container.getMutator().startNewValue(idx());
+    }
+    currentChildIndex = container.getMutator().add(idx());
+    for(final FieldWriter w : fields.values()) {
+      w.setPosition(currentChildIndex);
+    }
+  }
+
+
+  public void end() {
+    // noop
+  }
+  <#else>
+
+  public void setValueCount(int count) {
+    container.getMutator().setValueCount(count);
+  }
+
+  @Override
+  public void setPosition(int index) {
+    super.setPosition(index);
+    for(final FieldWriter w: fields.values()) {
+      w.setPosition(index);
+    }
+  }
+
+  @Override
+  public void start() {
+  }
+
+  @Override
+  public void end() {
+  }
+
+  </#if>
+
+  <#list vv.types as type><#list type.minor as minor>
+  <#assign lowerName = minor.class?uncap_first />
+  <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
+  <#assign upperName = minor.class?upper_case />
+  <#assign capName = minor.class?cap_first />
+  <#assign vectName = capName />
+  <#assign vectName = "Nullable${capName}" />
+
+  <#if minor.class?starts_with("Decimal") >
+  public ${minor.class}Writer ${lowerName}(String name) {
+    // returns existing writer
+    final FieldWriter writer = fields.get(name.toLowerCase());
+    assert writer != null;
+    return writer;
+  }
+
+  public ${minor.class}Writer ${lowerName}(String name, int scale, int precision) {
+    final MajorType ${upperName}_TYPE = new MajorType(MinorType.${upperName}, DataMode.OPTIONAL, scale, precision, null, null);
+  <#else>
+  private static final MajorType ${upperName}_TYPE = Types.optional(MinorType.${upperName});
+  @Override
+  public ${minor.class}Writer ${lowerName}(String name) {
+  </#if>
+    FieldWriter writer = fields.get(name.toLowerCase());
+    if(writer == null) {
+      ValueVector vector;
+      ValueVector currentVector = container.getChild(name);
+      if (unionEnabled){
+        ${vectName}Vector v = container.addOrGet(name, ${upperName}_TYPE, ${vectName}Vector.class);
+        writer = new PromotableWriter(v, container);
+        vector = v;
+      } else {
+        ${vectName}Vector v = container.addOrGet(name, ${upperName}_TYPE, ${vectName}Vector.class);
+        writer = new ${vectName}WriterImpl(v, this);
+        vector = v;
+      }
+      if (currentVector == null || currentVector != vector) {
+        vector.allocateNewSafe();
+      } 
+      writer.setPosition(${index});
+      fields.put(name.toLowerCase(), writer);
+    }
+    return writer;
+  }
+
+  </#list></#list>
+
+}
+</#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/NullReader.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/NullReader.java b/java/vector/src/main/codegen/templates/NullReader.java
new file mode 100644
index 0000000..3ef6c7d
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/NullReader.java
@@ -0,0 +1,138 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<@pp.dropOutputFile />
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/NullReader.java" />
+
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+
+
+@SuppressWarnings("unused")
+public class NullReader extends AbstractBaseReader implements FieldReader{
+  
+  public static final NullReader INSTANCE = new NullReader();
+  public static final NullReader EMPTY_LIST_INSTANCE = new NullReader(Types.repeated(MinorType.NULL));
+  public static final NullReader EMPTY_MAP_INSTANCE = new NullReader(Types.required(MinorType.MAP));
+  private MajorType type;
+  
+  private NullReader(){
+    super();
+    type = Types.required(MinorType.NULL);
+  }
+
+  private NullReader(MajorType type){
+    super();
+    this.type = type;
+  }
+
+  @Override
+  public MajorType getType() {
+    return type;
+  }
+  
+  public void copyAsValue(MapWriter writer) {}
+
+  public void copyAsValue(ListWriter writer) {}
+
+  public void copyAsValue(UnionWriter writer) {}
+
+  <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
+  public void read(${name}Holder holder){
+    throw new UnsupportedOperationException("NullReader cannot write into non-nullable holder");
+  }
+
+  public void read(Nullable${name}Holder holder){
+    holder.isSet = 0;
+  }
+
+  public void read(int arrayIndex, ${name}Holder holder){
+    throw new ArrayIndexOutOfBoundsException();
+  }
+  
+  public void copyAsValue(${minor.class}Writer writer){}
+  public void copyAsField(String name, ${minor.class}Writer writer){}
+
+  public void read(int arrayIndex, Nullable${name}Holder holder){
+    throw new ArrayIndexOutOfBoundsException();
+  }
+  </#list></#list>
+  
+  public int size(){
+    return 0;
+  }
+  
+  public boolean isSet(){
+    return false;
+  }
+  
+  public boolean next(){
+    return false;
+  }
+  
+  public RepeatedMapReader map(){
+    return this;
+  }
+  
+  public RepeatedListReader list(){
+    return this;
+  }
+  
+  public MapReader map(String name){
+    return this;
+  }
+  
+  public ListReader list(String name){
+    return this;
+  }
+  
+  public FieldReader reader(String name){
+    return this;
+  }
+  
+  public FieldReader reader(){
+    return this;
+  }
+  
+  private void fail(String name){
+    throw new IllegalArgumentException(String.format("You tried to read a %s type when you are using a ValueReader of type %s.", name, this.getClass().getSimpleName()));
+  }
+  
+  <#list ["Object", "BigDecimal", "Integer", "Long", "Boolean", 
+          "Character", "DateTime", "Period", "Double", "Float",
+          "Text", "String", "Byte", "Short", "byte[]"] as friendlyType>
+  <#assign safeType=friendlyType />
+  <#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
+  
+  public ${friendlyType} read${safeType}(int arrayIndex){
+    return null;
+  }
+  
+  public ${friendlyType} read${safeType}(){
+    return null;
+  }
+  </#list>
+  
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/NullableValueVectors.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/NullableValueVectors.java b/java/vector/src/main/codegen/templates/NullableValueVectors.java
new file mode 100644
index 0000000..6893a25
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/NullableValueVectors.java
@@ -0,0 +1,630 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+<@pp.dropOutputFile />
+<#list vv.types as type>
+<#list type.minor as minor>
+
+<#assign className = "Nullable${minor.class}Vector" />
+<#assign valuesName = "${minor.class}Vector" />
+<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+
+<@pp.changeOutputFile name="/org/apache/arrow/vector/${className}.java" />
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector;
+
+<#include "/@includes/vv_imports.ftl" />
+
+/**
+ * Nullable${minor.class} implements a vector of values which could be null.  Elements in the vector
+ * are first checked against a fixed length vector of boolean values.  Then the element is retrieved
+ * from the base class (if not null).
+ *
+ * NB: this class is automatically generated from ${.template_name} and ValueVectorTypes.tdd using FreeMarker.
+ */
+@SuppressWarnings("unused")
+public final class ${className} extends BaseDataValueVector implements <#if type.major == "VarLen">VariableWidth<#else>FixedWidth</#if>Vector, NullableVector{
+  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${className}.class);
+
+  private final FieldReader reader = new Nullable${minor.class}ReaderImpl(Nullable${minor.class}Vector.this);
+
+  private final MaterializedField bitsField = MaterializedField.create("$bits$", new MajorType(MinorType.UINT1, DataMode.REQUIRED));
+  private final UInt1Vector bits = new UInt1Vector(bitsField, allocator);
+  private final ${valuesName} values = new ${minor.class}Vector(field, allocator);
+
+  private final Mutator mutator = new Mutator();
+  private final Accessor accessor = new Accessor();
+
+  public ${className}(MaterializedField field, BufferAllocator allocator) {
+    super(field, allocator);
+  }
+
+  @Override
+  public FieldReader getReader(){
+    return reader;
+  }
+
+  @Override
+  public int getValueCapacity(){
+    return Math.min(bits.getValueCapacity(), values.getValueCapacity());
+  }
+
+  @Override
+  public ArrowBuf[] getBuffers(boolean clear) {
+    final ArrowBuf[] buffers = ObjectArrays.concat(bits.getBuffers(false), values.getBuffers(false), ArrowBuf.class);
+    if (clear) {
+      for (final ArrowBuf buffer:buffers) {
+        buffer.retain(1);
+      }
+      clear();
+    }
+    return buffers;
+  }
+
+  @Override
+  public void close() {
+    bits.close();
+    values.close();
+    super.close();
+  }
+
+  @Override
+  public void clear() {
+    bits.clear();
+    values.clear();
+    super.clear();
+  }
+
+  @Override
+  public int getBufferSize(){
+    return values.getBufferSize() + bits.getBufferSize();
+  }
+
+  @Override
+  public int getBufferSizeFor(final int valueCount) {
+    if (valueCount == 0) {
+      return 0;
+    }
+
+    return values.getBufferSizeFor(valueCount)
+        + bits.getBufferSizeFor(valueCount);
+  }
+
+  @Override
+  public ArrowBuf getBuffer() {
+    return values.getBuffer();
+  }
+
+  @Override
+  public ${valuesName} getValuesVector() {
+    return values;
+  }
+
+  @Override
+  public void setInitialCapacity(int numRecords) {
+    bits.setInitialCapacity(numRecords);
+    values.setInitialCapacity(numRecords);
+  }
+
+//  @Override
+//  public SerializedField.Builder getMetadataBuilder() {
+//    return super.getMetadataBuilder()
+//      .addChild(bits.getMetadata())
+//      .addChild(values.getMetadata());
+//  }
+
+  @Override
+  public void allocateNew() {
+    if(!allocateNewSafe()){
+      throw new OutOfMemoryException("Failure while allocating buffer.");
+    }
+  }
+
+  @Override
+  public boolean allocateNewSafe() {
+    /* Boolean to keep track if all the memory allocations were successful
+     * Used in the case of composite vectors when we need to allocate multiple
+     * buffers for multiple vectors. If one of the allocations failed we need to
+     * clear all the memory that we allocated
+     */
+    boolean success = false;
+    try {
+      success = values.allocateNewSafe() && bits.allocateNewSafe();
+    } finally {
+      if (!success) {
+        clear();
+      }
+    }
+    bits.zeroVector();
+    mutator.reset();
+    accessor.reset();
+    return success;
+  }
+
+  <#if type.major == "VarLen">
+  @Override
+  public void allocateNew(int totalBytes, int valueCount) {
+    try {
+      values.allocateNew(totalBytes, valueCount);
+      bits.allocateNew(valueCount);
+    } catch(RuntimeException e) {
+      clear();
+      throw e;
+    }
+    bits.zeroVector();
+    mutator.reset();
+    accessor.reset();
+  }
+
+  public void reset() {
+    bits.zeroVector();
+    mutator.reset();
+    accessor.reset();
+    super.reset();
+  }
+
+  @Override
+  public int getByteCapacity(){
+    return values.getByteCapacity();
+  }
+
+  @Override
+  public int getCurrentSizeInBytes(){
+    return values.getCurrentSizeInBytes();
+  }
+
+  <#else>
+  @Override
+  public void allocateNew(int valueCount) {
+    try {
+      values.allocateNew(valueCount);
+      bits.allocateNew(valueCount+1);
+    } catch(OutOfMemoryException e) {
+      clear();
+      throw e;
+    }
+    bits.zeroVector();
+    mutator.reset();
+    accessor.reset();
+  }
+
+  @Override
+  public void reset() {
+    bits.zeroVector();
+    mutator.reset();
+    accessor.reset();
+    super.reset();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void zeroVector() {
+    bits.zeroVector();
+    values.zeroVector();
+  }
+  </#if>
+
+
+//  @Override
+//  public void load(SerializedField metadata, ArrowBuf buffer) {
+//    clear();
+    // the bits vector is the first child (the order in which the children are added in getMetadataBuilder is significant)
+//    final SerializedField bitsField = metadata.getChild(0);
+//    bits.load(bitsField, buffer);
+//
+//    final int capacity = buffer.capacity();
+//    final int bitsLength = bitsField.getBufferLength();
+//    final SerializedField valuesField = metadata.getChild(1);
+//    values.load(valuesField, buffer.slice(bitsLength, capacity - bitsLength));
+//  }
+
+  @Override
+  public TransferPair getTransferPair(BufferAllocator allocator){
+    return new TransferImpl(getField(), allocator);
+  }
+
+  @Override
+  public TransferPair getTransferPair(String ref, BufferAllocator allocator){
+    return new TransferImpl(getField().withPath(ref), allocator);
+  }
+
+  @Override
+  public TransferPair makeTransferPair(ValueVector to) {
+    return new TransferImpl((Nullable${minor.class}Vector) to);
+  }
+
+  public void transferTo(Nullable${minor.class}Vector target){
+    bits.transferTo(target.bits);
+    values.transferTo(target.values);
+    <#if type.major == "VarLen">
+    target.mutator.lastSet = mutator.lastSet;
+    </#if>
+    clear();
+  }
+
+  public void splitAndTransferTo(int startIndex, int length, Nullable${minor.class}Vector target) {
+    bits.splitAndTransferTo(startIndex, length, target.bits);
+    values.splitAndTransferTo(startIndex, length, target.values);
+    <#if type.major == "VarLen">
+    target.mutator.lastSet = length - 1;
+    </#if>
+  }
+
+  private class TransferImpl implements TransferPair {
+    Nullable${minor.class}Vector to;
+
+    public TransferImpl(MaterializedField field, BufferAllocator allocator){
+      to = new Nullable${minor.class}Vector(field, allocator);
+    }
+
+    public TransferImpl(Nullable${minor.class}Vector to){
+      this.to = to;
+    }
+
+    @Override
+    public Nullable${minor.class}Vector getTo(){
+      return to;
+    }
+
+    @Override
+    public void transfer(){
+      transferTo(to);
+    }
+
+    @Override
+    public void splitAndTransfer(int startIndex, int length) {
+      splitAndTransferTo(startIndex, length, to);
+    }
+
+    @Override
+    public void copyValueSafe(int fromIndex, int toIndex) {
+      to.copyFromSafe(fromIndex, toIndex, Nullable${minor.class}Vector.this);
+    }
+  }
+
+  @Override
+  public Accessor getAccessor(){
+    return accessor;
+  }
+
+  @Override
+  public Mutator getMutator(){
+    return mutator;
+  }
+
+  public ${minor.class}Vector convertToRequiredVector(){
+    ${minor.class}Vector v = new ${minor.class}Vector(getField().getOtherNullableVersion(), allocator);
+    if (v.data != null) {
+      v.data.release(1);
+    }
+    v.data = values.data;
+    v.data.retain(1);
+    clear();
+    return v;
+  }
+
+  public void copyFrom(int fromIndex, int thisIndex, Nullable${minor.class}Vector from){
+    final Accessor fromAccessor = from.getAccessor();
+    if (!fromAccessor.isNull(fromIndex)) {
+      mutator.set(thisIndex, fromAccessor.get(fromIndex));
+    }
+  }
+
+  public void copyFromSafe(int fromIndex, int thisIndex, ${minor.class}Vector from){
+    <#if type.major == "VarLen">
+    mutator.fillEmpties(thisIndex);
+    </#if>
+    values.copyFromSafe(fromIndex, thisIndex, from);
+    bits.getMutator().setSafe(thisIndex, 1);
+  }
+
+  public void copyFromSafe(int fromIndex, int thisIndex, Nullable${minor.class}Vector from){
+    <#if type.major == "VarLen">
+    mutator.fillEmpties(thisIndex);
+    </#if>
+    bits.copyFromSafe(fromIndex, thisIndex, from.bits);
+    values.copyFromSafe(fromIndex, thisIndex, from.values);
+  }
+
+  public final class Accessor extends BaseDataValueVector.BaseAccessor <#if type.major = "VarLen">implements VariableWidthVector.VariableWidthAccessor</#if> {
+    final UInt1Vector.Accessor bAccessor = bits.getAccessor();
+    final ${valuesName}.Accessor vAccessor = values.getAccessor();
+
+    /**
+     * Get the element at the specified position.
+     *
+     * @param   index   position of the value
+     * @return  value of the element, if not null
+     * @throws  NullValueException if the value is null
+     */
+    public <#if type.major == "VarLen">byte[]<#else>${minor.javaType!type.javaType}</#if> get(int index) {
+      if (isNull(index)) {
+          throw new IllegalStateException("Can't get a null value");
+      }
+      return vAccessor.get(index);
+    }
+
+    @Override
+    public boolean isNull(int index) {
+      return isSet(index) == 0;
+    }
+
+    public int isSet(int index){
+      return bAccessor.get(index);
+    }
+
+    <#if type.major == "VarLen">
+    public long getStartEnd(int index){
+      return vAccessor.getStartEnd(index);
+    }
+
+    @Override
+    public int getValueLength(int index) {
+      return values.getAccessor().getValueLength(index);
+    }
+    </#if>
+
+    public void get(int index, Nullable${minor.class}Holder holder){
+      vAccessor.get(index, holder);
+      holder.isSet = bAccessor.get(index);
+
+      <#if minor.class.startsWith("Decimal")>
+      holder.scale = getField().getScale();
+      holder.precision = getField().getPrecision();
+      </#if>
+    }
+
+    @Override
+    public ${friendlyType} getObject(int index) {
+      if (isNull(index)) {
+          return null;
+      }else{
+        return vAccessor.getObject(index);
+      }
+    }
+
+    <#if minor.class == "Interval" || minor.class == "IntervalDay" || minor.class == "IntervalYear">
+    public StringBuilder getAsStringBuilder(int index) {
+      if (isNull(index)) {
+          return null;
+      }else{
+        return vAccessor.getAsStringBuilder(index);
+      }
+    }
+    </#if>
+
+    @Override
+    public int getValueCount(){
+      return bits.getAccessor().getValueCount();
+    }
+
+    public void reset(){}
+  }
+
+  public final class Mutator extends BaseDataValueVector.BaseMutator implements NullableVectorDefinitionSetter<#if type.major = "VarLen">, VariableWidthVector.VariableWidthMutator</#if> {
+    private int setCount;
+    <#if type.major = "VarLen"> private int lastSet = -1;</#if>
+
+    private Mutator(){
+    }
+
+    public ${valuesName} getVectorWithValues(){
+      return values;
+    }
+
+    @Override
+    public void setIndexDefined(int index){
+      bits.getMutator().set(index, 1);
+    }
+
+    /**
+     * Set the variable length element at the specified index to the supplied byte array.
+     *
+     * @param index   position of the bit to set
+     * @param bytes   array of bytes to write
+     */
+    public void set(int index, <#if type.major == "VarLen">byte[]<#elseif (type.width < 4)>int<#else>${minor.javaType!type.javaType}</#if> value) {
+      setCount++;
+      final ${valuesName}.Mutator valuesMutator = values.getMutator();
+      final UInt1Vector.Mutator bitsMutator = bits.getMutator();
+      <#if type.major == "VarLen">
+      for (int i = lastSet + 1; i < index; i++) {
+        valuesMutator.set(i, emptyByteArray);
+      }
+      </#if>
+      bitsMutator.set(index, 1);
+      valuesMutator.set(index, value);
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    <#if type.major == "VarLen">
+
+    private void fillEmpties(int index){
+      final ${valuesName}.Mutator valuesMutator = values.getMutator();
+      for (int i = lastSet; i < index; i++) {
+        valuesMutator.setSafe(i + 1, emptyByteArray);
+      }
+      while(index > bits.getValueCapacity()) {
+        bits.reAlloc();
+      }
+      lastSet = index;
+    }
+
+    @Override
+    public void setValueLengthSafe(int index, int length) {
+      values.getMutator().setValueLengthSafe(index, length);
+      lastSet = index;
+    }
+    </#if>
+
+    public void setSafe(int index, byte[] value, int start, int length) {
+      <#if type.major != "VarLen">
+      throw new UnsupportedOperationException();
+      <#else>
+      fillEmpties(index);
+
+      bits.getMutator().setSafe(index, 1);
+      values.getMutator().setSafe(index, value, start, length);
+      setCount++;
+      <#if type.major == "VarLen">lastSet = index;</#if>
+      </#if>
+    }
+
+    public void setSafe(int index, ByteBuffer value, int start, int length) {
+      <#if type.major != "VarLen">
+      throw new UnsupportedOperationException();
+      <#else>
+      fillEmpties(index);
+
+      bits.getMutator().setSafe(index, 1);
+      values.getMutator().setSafe(index, value, start, length);
+      setCount++;
+      <#if type.major == "VarLen">lastSet = index;</#if>
+      </#if>
+    }
+
+    public void setNull(int index){
+      bits.getMutator().setSafe(index, 0);
+    }
+
+    public void setSkipNull(int index, ${minor.class}Holder holder){
+      values.getMutator().set(index, holder);
+    }
+
+    public void setSkipNull(int index, Nullable${minor.class}Holder holder){
+      values.getMutator().set(index, holder);
+    }
+
+
+    public void set(int index, Nullable${minor.class}Holder holder){
+      final ${valuesName}.Mutator valuesMutator = values.getMutator();
+      <#if type.major == "VarLen">
+      for (int i = lastSet + 1; i < index; i++) {
+        valuesMutator.set(i, emptyByteArray);
+      }
+      </#if>
+      bits.getMutator().set(index, holder.isSet);
+      valuesMutator.set(index, holder);
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    public void set(int index, ${minor.class}Holder holder){
+      final ${valuesName}.Mutator valuesMutator = values.getMutator();
+      <#if type.major == "VarLen">
+      for (int i = lastSet + 1; i < index; i++) {
+        valuesMutator.set(i, emptyByteArray);
+      }
+      </#if>
+      bits.getMutator().set(index, 1);
+      valuesMutator.set(index, holder);
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    public boolean isSafe(int outIndex) {
+      return outIndex < Nullable${minor.class}Vector.this.getValueCapacity();
+    }
+
+    <#assign fields = minor.fields!type.fields />
+    public void set(int index, int isSet<#list fields as field><#if field.include!true >, ${field.type} ${field.name}Field</#if></#list> ){
+      final ${valuesName}.Mutator valuesMutator = values.getMutator();
+      <#if type.major == "VarLen">
+      for (int i = lastSet + 1; i < index; i++) {
+        valuesMutator.set(i, emptyByteArray);
+      }
+      </#if>
+      bits.getMutator().set(index, isSet);
+      valuesMutator.set(index<#list fields as field><#if field.include!true >, ${field.name}Field</#if></#list>);
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    public void setSafe(int index, int isSet<#list fields as field><#if field.include!true >, ${field.type} ${field.name}Field</#if></#list> ) {
+      <#if type.major == "VarLen">
+      fillEmpties(index);
+      </#if>
+
+      bits.getMutator().setSafe(index, isSet);
+      values.getMutator().setSafe(index<#list fields as field><#if field.include!true >, ${field.name}Field</#if></#list>);
+      setCount++;
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+
+    public void setSafe(int index, Nullable${minor.class}Holder value) {
+
+      <#if type.major == "VarLen">
+      fillEmpties(index);
+      </#if>
+      bits.getMutator().setSafe(index, value.isSet);
+      values.getMutator().setSafe(index, value);
+      setCount++;
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    public void setSafe(int index, ${minor.class}Holder value) {
+
+      <#if type.major == "VarLen">
+      fillEmpties(index);
+      </#if>
+      bits.getMutator().setSafe(index, 1);
+      values.getMutator().setSafe(index, value);
+      setCount++;
+      <#if type.major == "VarLen">lastSet = index;</#if>
+    }
+
+    <#if !(type.major == "VarLen" || minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense" || minor.class == "Interval" || minor.class == "IntervalDay")>
+      public void setSafe(int index, ${minor.javaType!type.javaType} value) {
+        <#if type.major == "VarLen">
+        fillEmpties(index);
+        </#if>
+        bits.getMutator().setSafe(index, 1);
+        values.getMutator().setSafe(index, value);
+        setCount++;
+      }
+
+    </#if>
+
+    @Override
+    public void setValueCount(int valueCount) {
+      assert valueCount >= 0;
+      <#if type.major == "VarLen">
+      fillEmpties(valueCount);
+      </#if>
+      values.getMutator().setValueCount(valueCount);
+      bits.getMutator().setValueCount(valueCount);
+    }
+
+    @Override
+    public void generateTestData(int valueCount){
+      bits.getMutator().generateTestDataAlt(valueCount);
+      values.getMutator().generateTestData(valueCount);
+      <#if type.major = "VarLen">lastSet = valueCount;</#if>
+      setValueCount(valueCount);
+    }
+
+    @Override
+    public void reset(){
+      setCount = 0;
+      <#if type.major = "VarLen">lastSet = -1;</#if>
+    }
+  }
+}
+</#list>
+</#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/RepeatedValueVectors.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/RepeatedValueVectors.java b/java/vector/src/main/codegen/templates/RepeatedValueVectors.java
new file mode 100644
index 0000000..5ac80f5
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/RepeatedValueVectors.java
@@ -0,0 +1,421 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<@pp.dropOutputFile />
+<#list vv.types as type>
+<#list type.minor as minor>
+<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#assign fields = minor.fields!type.fields />
+
+<@pp.changeOutputFile name="/org/apache/arrow/vector/Repeated${minor.class}Vector.java" />
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector;
+
+<#include "/@includes/vv_imports.ftl" />
+
+/**
+ * Repeated${minor.class} implements a vector with multple values per row (e.g. JSON array or
+ * repeated protobuf field).  The implementation uses two additional value vectors; one to convert
+ * the index offset to the underlying element offset, and another to store the number of values
+ * in the vector.
+ *
+ * NB: this class is automatically generated from ${.template_name} and ValueVectorTypes.tdd using FreeMarker.
+ */
+
+public final class Repeated${minor.class}Vector extends BaseRepeatedValueVector implements Repeated<#if type.major == "VarLen">VariableWidth<#else>FixedWidth</#if>VectorLike {
+  //private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Repeated${minor.class}Vector.class);
+
+  // we maintain local reference to concrete vector type for performance reasons.
+  private ${minor.class}Vector values;
+  private final FieldReader reader = new Repeated${minor.class}ReaderImpl(Repeated${minor.class}Vector.this);
+  private final Mutator mutator = new Mutator();
+  private final Accessor accessor = new Accessor();
+
+  public Repeated${minor.class}Vector(MaterializedField field, BufferAllocator allocator) {
+    super(field, allocator);
+    addOrGetVector(VectorDescriptor.create(new MajorType(field.getType().getMinorType(), DataMode.REQUIRED)));
+  }
+
+  @Override
+  public Mutator getMutator() {
+    return mutator;
+  }
+
+  @Override
+  public Accessor getAccessor() {
+    return accessor;
+  }
+
+  @Override
+  public FieldReader getReader() {
+    return reader;
+  }
+
+  @Override
+  public ${minor.class}Vector getDataVector() {
+    return values;
+  }
+
+  @Override
+  public TransferPair getTransferPair(BufferAllocator allocator) {
+    return new TransferImpl(getField(), allocator);
+  }
+
+  @Override
+  public TransferPair getTransferPair(String ref, BufferAllocator allocator){
+    return new TransferImpl(getField().withPath(ref), allocator);
+  }
+
+  @Override
+  public TransferPair makeTransferPair(ValueVector to) {
+    return new TransferImpl((Repeated${minor.class}Vector) to);
+  }
+
+  @Override
+  public AddOrGetResult<${minor.class}Vector> addOrGetVector(VectorDescriptor descriptor) {
+    final AddOrGetResult<${minor.class}Vector> result = super.addOrGetVector(descriptor);
+    if (result.isCreated()) {
+      values = result.getVector();
+    }
+    return result;
+  }
+
+  public void transferTo(Repeated${minor.class}Vector target) {
+    target.clear();
+    offsets.transferTo(target.offsets);
+    values.transferTo(target.values);
+    clear();
+  }
+
+  public void splitAndTransferTo(final int startIndex, final int groups, Repeated${minor.class}Vector to) {
+    final UInt4Vector.Accessor a = offsets.getAccessor();
+    final UInt4Vector.Mutator m = to.offsets.getMutator();
+
+    final int startPos = a.get(startIndex);
+    final int endPos = a.get(startIndex + groups);
+    final int valuesToCopy = endPos - startPos;
+
+    values.splitAndTransferTo(startPos, valuesToCopy, to.values);
+    to.offsets.clear();
+    to.offsets.allocateNew(groups + 1);
+    int normalizedPos = 0;
+    for (int i=0; i < groups + 1;i++ ) {
+      normalizedPos = a.get(startIndex+i) - startPos;
+      m.set(i, normalizedPos);
+    }
+    m.setValueCount(groups == 0 ? 0 : groups + 1);
+  }
+
+  private class TransferImpl implements TransferPair {
+    final Repeated${minor.class}Vector to;
+
+    public TransferImpl(MaterializedField field, BufferAllocator allocator) {
+      this.to = new Repeated${minor.class}Vector(field, allocator);
+    }
+
+    public TransferImpl(Repeated${minor.class}Vector to) {
+      this.to = to;
+    }
+
+    @Override
+    public Repeated${minor.class}Vector getTo() {
+      return to;
+    }
+
+    @Override
+    public void transfer() {
+      transferTo(to);
+    }
+
+    @Override
+    public void splitAndTransfer(int startIndex, int length) {
+      splitAndTransferTo(startIndex, length, to);
+    }
+
+    @Override
+    public void copyValueSafe(int fromIndex, int toIndex) {
+      to.copyFromSafe(fromIndex, toIndex, Repeated${minor.class}Vector.this);
+    }
+  }
+
+    public void copyFrom(int inIndex, int outIndex, Repeated${minor.class}Vector v) {
+      final Accessor vAccessor = v.getAccessor();
+      final int count = vAccessor.getInnerValueCountAt(inIndex);
+      mutator.startNewValue(outIndex);
+      for (int i = 0; i < count; i++) {
+        mutator.add(outIndex, vAccessor.get(inIndex, i));
+      }
+    }
+
+    public void copyFromSafe(int inIndex, int outIndex, Repeated${minor.class}Vector v) {
+      final Accessor vAccessor = v.getAccessor();
+      final int count = vAccessor.getInnerValueCountAt(inIndex);
+      mutator.startNewValue(outIndex);
+      for (int i = 0; i < count; i++) {
+        mutator.addSafe(outIndex, vAccessor.get(inIndex, i));
+      }
+    }
+
+  public boolean allocateNewSafe() {
+    /* boolean to keep track if all the memory allocation were successful
+     * Used in the case of composite vectors when we need to allocate multiple
+     * buffers for multiple vectors. If one of the allocations failed we need to
+     * clear all the memory that we allocated
+     */
+    boolean success = false;
+    try {
+      if(!offsets.allocateNewSafe()) return false;
+      if(!values.allocateNewSafe()) return false;
+      success = true;
+    } finally {
+      if (!success) {
+        clear();
+      }
+    }
+    offsets.zeroVector();
+    mutator.reset();
+    return true;
+  }
+
+  @Override
+  public void allocateNew() {
+    try {
+      offsets.allocateNew();
+      values.allocateNew();
+    } catch (OutOfMemoryException e) {
+      clear();
+      throw e;
+    }
+    offsets.zeroVector();
+    mutator.reset();
+  }
+
+  <#if type.major == "VarLen">
+//  @Override
+//  protected SerializedField.Builder getMetadataBuilder() {
+//    return super.getMetadataBuilder()
+//            .setVarByteLength(values.getVarByteLength());
+//  }
+
+  public void allocateNew(int totalBytes, int valueCount, int innerValueCount) {
+    try {
+      offsets.allocateNew(valueCount + 1);
+      values.allocateNew(totalBytes, innerValueCount);
+    } catch (OutOfMemoryException e) {
+      clear();
+      throw e;
+    }
+    offsets.zeroVector();
+    mutator.reset();
+  }
+
+  public int getByteCapacity(){
+    return values.getByteCapacity();
+  }
+
+  <#else>
+
+  @Override
+  public void allocateNew(int valueCount, int innerValueCount) {
+    clear();
+    /* boolean to keep track if all the memory allocation were successful
+     * Used in the case of composite vectors when we need to allocate multiple
+     * buffers for multiple vectors. If one of the allocations failed we need to//
+     * clear all the memory that we allocated
+     */
+    boolean success = false;
+    try {
+      offsets.allocateNew(valueCount + 1);
+      values.allocateNew(innerValueCount);
+    } catch(OutOfMemoryException e){
+      clear();
+      throw e;
+    }
+    offsets.zeroVector();
+    mutator.reset();
+  }
+
+  </#if>
+
+  // This is declared a subclass of the accessor declared inside of FixedWidthVector, this is also used for
+  // variable length vectors, as they should ahve consistent interface as much as possible, if they need to diverge
+  // in the future, the interface shold be declared in the respective value vector superclasses for fixed and variable
+  // and we should refer to each in the generation template
+  public final class Accessor extends BaseRepeatedValueVector.BaseRepeatedAccessor {
+    @Override
+    public List<${friendlyType}> getObject(int index) {
+      final List<${friendlyType}> vals = new JsonStringArrayList<>();
+      final UInt4Vector.Accessor offsetsAccessor = offsets.getAccessor();
+      final int start = offsetsAccessor.get(index);
+      final int end = offsetsAccessor.get(index + 1);
+      final ${minor.class}Vector.Accessor valuesAccessor = values.getAccessor();
+      for(int i = start; i < end; i++) {
+        vals.add(valuesAccessor.getObject(i));
+      }
+      return vals;
+    }
+
+    public ${friendlyType} getSingleObject(int index, int arrayIndex) {
+      final int start = offsets.getAccessor().get(index);
+      return values.getAccessor().getObject(start + arrayIndex);
+    }
+
+    /**
+     * Get a value for the given record.  Each element in the repeated field is accessed by
+     * the positionIndex param.
+     *
+     * @param  index           record containing the repeated field
+     * @param  positionIndex   position within the repeated field
+     * @return element at the given position in the given record
+     */
+    public <#if type.major == "VarLen">byte[]
+           <#else>${minor.javaType!type.javaType}
+           </#if> get(int index, int positionIndex) {
+      return values.getAccessor().get(offsets.getAccessor().get(index) + positionIndex);
+    }
+
+    public void get(int index, Repeated${minor.class}Holder holder) {
+      holder.start = offsets.getAccessor().get(index);
+      holder.end =  offsets.getAccessor().get(index+1);
+      holder.vector = values;
+    }
+
+    public void get(int index, int positionIndex, ${minor.class}Holder holder) {
+      final int offset = offsets.getAccessor().get(index);
+      assert offset >= 0;
+      assert positionIndex < getInnerValueCountAt(index);
+      values.getAccessor().get(offset + positionIndex, holder);
+    }
+
+    public void get(int index, int positionIndex, Nullable${minor.class}Holder holder) {
+      final int offset = offsets.getAccessor().get(index);
+      assert offset >= 0;
+      if (positionIndex >= getInnerValueCountAt(index)) {
+        holder.isSet = 0;
+        return;
+      }
+      values.getAccessor().get(offset + positionIndex, holder);
+    }
+  }
+
+  public final class Mutator extends BaseRepeatedValueVector.BaseRepeatedMutator implements RepeatedMutator {
+    private Mutator() {}
+
+    /**
+     * Add an element to the given record index.  This is similar to the set() method in other
+     * value vectors, except that it permits setting multiple values for a single record.
+     *
+     * @param index   record of the element to add
+     * @param value   value to add to the given row
+     */
+    public void add(int index, <#if type.major == "VarLen">byte[]<#elseif (type.width < 4)>int<#else>${minor.javaType!type.javaType}</#if> value) {
+      int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().set(nextOffset, value);
+      offsets.getMutator().set(index+1, nextOffset+1);
+    }
+
+    <#if type.major == "VarLen">
+    public void addSafe(int index, byte[] bytes) {
+      addSafe(index, bytes, 0, bytes.length);
+    }
+
+    public void addSafe(int index, byte[] bytes, int start, int length) {
+      final int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().setSafe(nextOffset, bytes, start, length);
+      offsets.getMutator().setSafe(index+1, nextOffset+1);
+    }
+
+    <#else>
+
+    public void addSafe(int index, ${minor.javaType!type.javaType} srcValue) {
+      final int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().setSafe(nextOffset, srcValue);
+      offsets.getMutator().setSafe(index+1, nextOffset+1);
+    }
+
+    </#if>
+
+    public void setSafe(int index, Repeated${minor.class}Holder h) {
+      final ${minor.class}Holder ih = new ${minor.class}Holder();
+      final ${minor.class}Vector.Accessor hVectorAccessor = h.vector.getAccessor();
+      mutator.startNewValue(index);
+      for(int i = h.start; i < h.end; i++){
+        hVectorAccessor.get(i, ih);
+        mutator.addSafe(index, ih);
+      }
+    }
+
+    public void addSafe(int index, ${minor.class}Holder holder) {
+      int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().setSafe(nextOffset, holder);
+      offsets.getMutator().setSafe(index+1, nextOffset+1);
+    }
+
+    public void addSafe(int index, Nullable${minor.class}Holder holder) {
+      final int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().setSafe(nextOffset, holder);
+      offsets.getMutator().setSafe(index+1, nextOffset+1);
+    }
+
+    <#if (fields?size > 1) && !(minor.class == "Decimal9" || minor.class == "Decimal18" || minor.class == "Decimal28Sparse" || minor.class == "Decimal38Sparse" || minor.class == "Decimal28Dense" || minor.class == "Decimal38Dense")>
+    public void addSafe(int arrayIndex, <#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>) {
+      int nextOffset = offsets.getAccessor().get(arrayIndex+1);
+      values.getMutator().setSafe(nextOffset, <#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
+      offsets.getMutator().setSafe(arrayIndex+1, nextOffset+1);
+    }
+    </#if>
+
+    protected void add(int index, ${minor.class}Holder holder) {
+      int nextOffset = offsets.getAccessor().get(index+1);
+      values.getMutator().set(nextOffset, holder);
+      offsets.getMutator().set(index+1, nextOffset+1);
+    }
+
+    public void add(int index, Repeated${minor.class}Holder holder) {
+
+      ${minor.class}Vector.Accessor accessor = holder.vector.getAccessor();
+      ${minor.class}Holder innerHolder = new ${minor.class}Holder();
+
+      for(int i = holder.start; i < holder.end; i++) {
+        accessor.get(i, innerHolder);
+        add(index, innerHolder);
+      }
+    }
+
+    @Override
+    public void generateTestData(final int valCount) {
+      final int[] sizes = {1, 2, 0, 6};
+      int size = 0;
+      int runningOffset = 0;
+      final UInt4Vector.Mutator offsetsMutator = offsets.getMutator();
+      for(int i = 1; i < valCount + 1; i++, size++) {
+        runningOffset += sizes[size % sizes.length];
+        offsetsMutator.set(i, runningOffset);
+      }
+      values.getMutator().generateTestData(valCount * 9);
+      setValueCount(size);
+    }
+
+    @Override
+    public void reset() {
+    }
+  }
+}
+</#list>
+</#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/UnionListWriter.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/UnionListWriter.java b/java/vector/src/main/codegen/templates/UnionListWriter.java
new file mode 100644
index 0000000..9a6b08f
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/UnionListWriter.java
@@ -0,0 +1,185 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.UnsupportedOperationException;
+
+<@pp.dropOutputFile />
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/UnionListWriter.java" />
+
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+
+/*
+ * This class is generated using freemarker and the ${.template_name} template.
+ */
+
+@SuppressWarnings("unused")
+public class UnionListWriter extends AbstractFieldWriter {
+
+  private ListVector vector;
+  private UInt4Vector offsets;
+  private PromotableWriter writer;
+  private boolean inMap = false;
+  private String mapName;
+  private int lastIndex = 0;
+
+  public UnionListWriter(ListVector vector) {
+    super(null);
+    this.vector = vector;
+    this.writer = new PromotableWriter(vector.getDataVector(), vector);
+    this.offsets = vector.getOffsetVector();
+  }
+
+  public UnionListWriter(ListVector vector, AbstractFieldWriter parent) {
+    this(vector);
+  }
+
+  @Override
+  public void allocate() {
+    vector.allocateNew();
+  }
+
+  @Override
+  public void clear() {
+    vector.clear();
+  }
+
+  @Override
+  public MaterializedField getField() {
+    return null;
+  }
+
+  @Override
+  public int getValueCapacity() {
+    return vector.getValueCapacity();
+  }
+
+  @Override
+  public void close() throws Exception {
+
+  }
+
+  <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
+  <#assign fields = minor.fields!type.fields />
+  <#assign uncappedName = name?uncap_first/>
+
+  <#if !minor.class?starts_with("Decimal")>
+
+  @Override
+  public ${name}Writer <#if uncappedName == "int">integer<#else>${uncappedName}</#if>() {
+    return this;
+  }
+
+  @Override
+  public ${name}Writer <#if uncappedName == "int">integer<#else>${uncappedName}</#if>(String name) {
+    assert inMap;
+    mapName = name;
+    final int nextOffset = offsets.getAccessor().get(idx() + 1);
+    vector.getMutator().setNotNull(idx());
+    writer.setPosition(nextOffset);
+    ${name}Writer ${uncappedName}Writer = writer.<#if uncappedName == "int">integer<#else>${uncappedName}</#if>(name);
+    return ${uncappedName}Writer;
+  }
+
+  </#if>
+
+  </#list></#list>
+
+  @Override
+  public MapWriter map() {
+    inMap = true;
+    return this;
+  }
+
+  @Override
+  public ListWriter list() {
+    final int nextOffset = offsets.getAccessor().get(idx() + 1);
+    vector.getMutator().setNotNull(idx());
+    offsets.getMutator().setSafe(idx() + 1, nextOffset + 1);
+    writer.setPosition(nextOffset);
+    return writer;
+  }
+
+  @Override
+  public ListWriter list(String name) {
+    final int nextOffset = offsets.getAccessor().get(idx() + 1);
+    vector.getMutator().setNotNull(idx());
+    writer.setPosition(nextOffset);
+    ListWriter listWriter = writer.list(name);
+    return listWriter;
+  }
+
+  @Override
+  public MapWriter map(String name) {
+    MapWriter mapWriter = writer.map(name);
+    return mapWriter;
+  }
+
+  @Override
+  public void startList() {
+    vector.getMutator().startNewValue(idx());
+  }
+
+  @Override
+  public void endList() {
+
+  }
+
+  @Override
+  public void start() {
+    assert inMap;
+    final int nextOffset = offsets.getAccessor().get(idx() + 1);
+    vector.getMutator().setNotNull(idx());
+    offsets.getMutator().setSafe(idx() + 1, nextOffset);
+    writer.setPosition(nextOffset);
+  }
+
+  @Override
+  public void end() {
+    if (inMap) {
+      inMap = false;
+      final int nextOffset = offsets.getAccessor().get(idx() + 1);
+      offsets.getMutator().setSafe(idx() + 1, nextOffset + 1);
+    }
+  }
+
+  <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
+  <#assign fields = minor.fields!type.fields />
+  <#assign uncappedName = name?uncap_first/>
+
+  <#if !minor.class?starts_with("Decimal")>
+
+  @Override
+  public void write${name}(<#list fields as field>${field.type} ${field.name}<#if field_has_next>, </#if></#list>) {
+    assert !inMap;
+    final int nextOffset = offsets.getAccessor().get(idx() + 1);
+    vector.getMutator().setNotNull(idx());
+    writer.setPosition(nextOffset);
+    writer.write${name}(<#list fields as field>${field.name}<#if field_has_next>, </#if></#list>);
+    offsets.getMutator().setSafe(idx() + 1, nextOffset + 1);
+  }
+
+  </#if>
+
+  </#list></#list>
+
+}

http://git-wip-us.apache.org/repos/asf/arrow/blob/fa5f0299/java/vector/src/main/codegen/templates/UnionReader.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/UnionReader.java b/java/vector/src/main/codegen/templates/UnionReader.java
new file mode 100644
index 0000000..44c3e55
--- /dev/null
+++ b/java/vector/src/main/codegen/templates/UnionReader.java
@@ -0,0 +1,194 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+<@pp.dropOutputFile />
+<@pp.changeOutputFile name="/org/apache/arrow/vector/complex/impl/UnionReader.java" />
+
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.arrow.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+
+@SuppressWarnings("unused")
+public class UnionReader extends AbstractFieldReader {
+
+  private BaseReader[] readers = new BaseReader[43];
+  public UnionVector data;
+  
+  public UnionReader(UnionVector data) {
+    this.data = data;
+  }
+
+  private static MajorType[] TYPES = new MajorType[43];
+
+  static {
+    for (MinorType minorType : MinorType.values()) {
+      TYPES[minorType.ordinal()] = new MajorType(minorType, DataMode.OPTIONAL);
+    }
+  }
+
+  public MajorType getType() {
+    return TYPES[data.getTypeValue(idx())];
+  }
+
+  public boolean isSet(){
+    return !data.getAccessor().isNull(idx());
+  }
+
+  public void read(UnionHolder holder) {
+    holder.reader = this;
+    holder.isSet = this.isSet() ? 1 : 0;
+  }
+
+  public void read(int index, UnionHolder holder) {
+    getList().read(index, holder);
+  }
+
+  private FieldReader getReaderForIndex(int index) {
+    int typeValue = data.getTypeValue(index);
+    FieldReader reader = (FieldReader) readers[typeValue];
+    if (reader != null) {
+      return reader;
+    }
+    switch (MinorType.values()[typeValue]) {
+    case LATE:
+      return NullReader.INSTANCE;
+    case MAP:
+      return (FieldReader) getMap();
+    case LIST:
+      return (FieldReader) getList();
+    <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
+    <#assign uncappedName = name?uncap_first/>
+    <#if !minor.class?starts_with("Decimal")>
+    case ${name?upper_case}:
+      return (FieldReader) get${name}();
+    </#if>
+    </#list></#list>
+    default:
+      throw new UnsupportedOperationException("Unsupported type: " + MinorType.values()[typeValue]);
+    }
+  }
+
+  private SingleMapReaderImpl mapReader;
+
+  private MapReader getMap() {
+    if (mapReader == null) {
+      mapReader = (SingleMapReaderImpl) data.getMap().getReader();
+      mapReader.setPosition(idx());
+      readers[MinorType.MAP.ordinal()] = mapReader;
+    }
+    return mapReader;
+  }
+
+  private UnionListReader listReader;
+
+  private FieldReader getList() {
+    if (listReader == null) {
+      listReader = new UnionListReader(data.getList());
+      listReader.setPosition(idx());
+      readers[MinorType.LIST.ordinal()] = listReader;
+    }
+    return listReader;
+  }
+
+  @Override
+  public java.util.Iterator<String> iterator() {
+    return getMap().iterator();
+  }
+
+  @Override
+  public void copyAsValue(UnionWriter writer) {
+    writer.data.copyFrom(idx(), writer.idx(), data);
+  }
+
+  <#list ["Object", "BigDecimal", "Integer", "Long", "Boolean",
+          "Character", "DateTime", "Period", "Double", "Float",
+          "Text", "String", "Byte", "Short", "byte[]"] as friendlyType>
+  <#assign safeType=friendlyType />
+  <#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
+
+  @Override
+  public ${friendlyType} read${safeType}() {
+    return getReaderForIndex(idx()).read${safeType}();
+  }
+
+  </#list>
+
+  <#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
+          <#assign uncappedName = name?uncap_first/>
+  <#assign boxedType = (minor.boxedType!type.boxedType) />
+  <#assign javaType = (minor.javaType!type.javaType) />
+  <#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+  <#assign safeType=friendlyType />
+  <#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
+  <#if !minor.class?starts_with("Decimal")>
+
+  private Nullable${name}ReaderImpl ${uncappedName}Reader;
+
+  private Nullable${name}ReaderImpl get${name}() {
+    if (${uncappedName}Reader == null) {
+      ${uncappedName}Reader = new Nullable${name}ReaderImpl(data.get${name}Vector());
+      ${uncappedName}Reader.setPosition(idx());
+      readers[MinorType.${name?upper_case}.ordinal()] = ${uncappedName}Reader;
+    }
+    return ${uncappedName}Reader;
+  }
+
+  public void read(Nullable${name}Holder holder){
+    getReaderForIndex(idx()).read(holder);
+  }
+
+  public void copyAsValue(${name}Writer writer){
+    getReaderForIndex(idx()).copyAsValue(writer);
+  }
+  </#if>
+  </#list></#list>
+
+  @Override
+  public void copyAsValue(ListWriter writer) {
+    ComplexCopier.copy(this, (FieldWriter) writer);
+  }
+
+  @Override
+  public void setPosition(int index) {
+    super.setPosition(index);
+    for (BaseReader reader : readers) {
+      if (reader != null) {
+        reader.setPosition(index);
+      }
+    }
+  }
+  
+  public FieldReader reader(String name){
+    return getMap().reader(name);
+  }
+
+  public FieldReader reader() {
+    return getList().reader();
+  }
+
+  public boolean next() {
+    return getReaderForIndex(idx()).next();
+  }
+}
+
+
+


Mime
View raw message