1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 <@pp.dropOutputFile />
19 <@pp.changeOutputFile name="/org/apache/arrow/vector/types/pojo/ArrowType.java" />
20 <#include "/@includes/license.ftl" />
21 
22 package org.apache.arrow.vector.types.pojo;
23 
24 import com.google.flatbuffers.FlatBufferBuilder;
25 
26 import java.util.Objects;
27 
28 import org.apache.arrow.flatbuf.Type;
29 import org.apache.arrow.memory.BufferAllocator;
30 import org.apache.arrow.vector.types.*;
31 import org.apache.arrow.vector.FieldVector;
32 
33 import com.fasterxml.jackson.annotation.JsonCreator;
34 import com.fasterxml.jackson.annotation.JsonIgnore;
35 import com.fasterxml.jackson.annotation.JsonProperty;
36 import com.fasterxml.jackson.annotation.JsonSubTypes;
37 import com.fasterxml.jackson.annotation.JsonTypeInfo;
38 
39 /**
40  * Arrow types
41  * Source code generated using FreeMarker template ${.template_name}
42  **/
43 @JsonTypeInfo(
44   use = JsonTypeInfo.Id.NAME,
45   include = JsonTypeInfo.As.PROPERTY,
46   property = "name")
47 @JsonSubTypes({
48 <#list arrowTypes.types as type>
49   @JsonSubTypes.Type(value = ArrowType.${type.name?remove_ending("_")}.class, name = "${type.name?remove_ending("_")?lower_case}"),
50 </#list>
51 })
52 public abstract class ArrowType {
53 
54   public static abstract class PrimitiveType extends ArrowType {
55 
PrimitiveType()56     private PrimitiveType() {
57     }
58 
59     @Override
isComplex()60     public boolean isComplex() {
61       return false;
62     }
63   }
64 
65   public static abstract class ComplexType extends ArrowType {
66 
ComplexType()67     private ComplexType() {
68     }
69 
70     @Override
isComplex()71     public boolean isComplex() {
72       return true;
73     }
74   }
75 
76   public static enum ArrowTypeID {
77     <#list arrowTypes.types as type>
78     <#assign name = type.name>
79     ${name?remove_ending("_")}(Type.${name}),
80     </#list>
81     NONE(Type.NONE);
82 
83     private final byte flatbufType;
84 
getFlatbufID()85     public byte getFlatbufID() {
86       return this.flatbufType;
87     }
88 
ArrowTypeID(byte flatbufType)89     private ArrowTypeID(byte flatbufType) {
90       this.flatbufType = flatbufType;
91     }
92   }
93 
94   @JsonIgnore
getTypeID()95   public abstract ArrowTypeID getTypeID();
96   @JsonIgnore
isComplex()97   public abstract boolean isComplex();
getType(FlatBufferBuilder builder)98   public abstract int getType(FlatBufferBuilder builder);
accept(ArrowTypeVisitor<T> visitor)99   public abstract <T> T accept(ArrowTypeVisitor<T> visitor);
100 
101   /**
102    * to visit the ArrowTypes
103    * <code>
104    *   type.accept(new ArrowTypeVisitor&lt;Type&gt;() {
105    *   ...
106    *   });
107    * </code>
108    */
109   public static interface ArrowTypeVisitor<T> {
110   <#list arrowTypes.types as type>
111     T visit(${type.name?remove_ending("_")} type);
112   </#list>
visit(ExtensionType type)113     default T visit(ExtensionType type) {
114       return type.storageType().accept(this);
115     }
116   }
117 
118   /**
119    * to visit the Complex ArrowTypes and bundle Primitive ones in one case
120    */
121   public static abstract class ComplexTypeVisitor<T> implements ArrowTypeVisitor<T> {
122 
visit(PrimitiveType type)123     public T visit(PrimitiveType type) {
124       throw new UnsupportedOperationException("Unexpected Primitive type: " + type);
125     }
126 
127   <#list arrowTypes.types as type>
128     <#if !type.complex>
129     public final T visit(${type.name?remove_ending("_")} type) {
130       return visit((PrimitiveType) type);
131     }
132     </#if>
133   </#list>
134   }
135 
136   /**
137    * to visit the Primitive ArrowTypes and bundle Complex ones under one case
138    */
139   public static abstract class PrimitiveTypeVisitor<T> implements ArrowTypeVisitor<T> {
140 
visit(ComplexType type)141     public T visit(ComplexType type) {
142       throw new UnsupportedOperationException("Unexpected Complex type: " + type);
143     }
144 
145   <#list arrowTypes.types as type>
146     <#if type.complex>
147     public final T visit(${type.name?remove_ending("_")} type) {
148       return visit((ComplexType) type);
149     }
150     </#if>
151   </#list>
152   }
153 
154   <#list arrowTypes.types as type>
155   <#assign name = type.name?remove_ending("_")>
156   <#assign fields = type.fields>
157   public static class ${name} extends <#if type.complex>ComplexType<#else>PrimitiveType</#if> {
158     public static final ArrowTypeID TYPE_TYPE = ArrowTypeID.${name};
159     <#if type.fields?size == 0>
160     public static final ${name} INSTANCE = new ${name}();
161     <#else>
162 
163     <#list fields as field>
164     <#assign fieldType = field.valueType!field.type>
165     ${fieldType} ${field.name};
166     </#list>
167 
168 
169     <#if type.name == "Decimal">
170     // Needed to support golden file integration tests.
171     @JsonCreator
createDecimal( @sonPropertyR) int precision, @JsonProperty(R) int scale, @JsonProperty(R) Integer bitWidth)172     public static Decimal createDecimal(
173       @JsonProperty("precision") int precision,
174       @JsonProperty("scale") int scale,
175       @JsonProperty("bitWidth") Integer bitWidth) {
176 
177       return new Decimal(precision, scale, bitWidth == null ? 128 : bitWidth);
178     }
179 
180     /**
181      * Construct Decimal with 128 bits.
182      *
183      * This is kept mainly for the sake of backward compatibility.
184      * Please use {@link org.apache.arrow.vector.types.pojo.ArrowType.Decimal#Decimal(int, int, int)} instead.
185      *
186      * @deprecated This API will be removed in a future release.
187      */
188     @Deprecated
Decimal(int precision, int scale)189     public Decimal(int precision, int scale) {
190       this(precision, scale, 128);
191     }
192 
193     <#else>
194     @JsonCreator
195     </#if>
196     public ${type.name}(
197     <#list type.fields as field>
198     <#assign fieldType = field.valueType!field.type>
199       @JsonProperty("${field.name}") ${fieldType} ${field.name}<#if field_has_next>, </#if>
200     </#list>
201     ) {
202       <#list type.fields as field>
203       this.${field.name} = ${field.name};
204       </#list>
205     }
206 
207     <#list fields as field>
208     <#assign fieldType = field.valueType!field.type>
209     public ${fieldType} get${field.name?cap_first}() {
210       return ${field.name};
211     }
212     </#list>
213     </#if>
214 
215     @Override
getTypeID()216     public ArrowTypeID getTypeID() {
217       return TYPE_TYPE;
218     }
219 
220     @Override
getType(FlatBufferBuilder builder)221     public int getType(FlatBufferBuilder builder) {
222       <#list type.fields as field>
223       <#if field.type == "String">
224       int ${field.name} = this.${field.name} == null ? -1 : builder.createString(this.${field.name});
225       </#if>
226       <#if field.type == "int[]">
227       int ${field.name} = this.${field.name} == null ? -1 : org.apache.arrow.flatbuf.${type.name}.create${field.name?cap_first}Vector(builder, this.${field.name});
228       </#if>
229       </#list>
230       org.apache.arrow.flatbuf.${type.name}.start${type.name}(builder);
231       <#list type.fields as field>
232       <#if field.type == "String" || field.type == "int[]">
233       if (this.${field.name} != null) {
234         org.apache.arrow.flatbuf.${type.name}.add${field.name?cap_first}(builder, ${field.name});
235       }
236       <#else>
237       org.apache.arrow.flatbuf.${type.name}.add${field.name?cap_first}(builder, this.${field.name}<#if field.valueType??>.getFlatbufID()</#if>);
238       </#if>
239       </#list>
240       return org.apache.arrow.flatbuf.${type.name}.end${type.name}(builder);
241     }
242 
243     public String toString() {
244       return "${name}"
245       <#if fields?size != 0>
246         + "("
247       <#list fields as field>
248         +   <#if field.type == "int[]">java.util.Arrays.toString(${field.name})<#else>${field.name}</#if><#if field_has_next> + ", " </#if>
249       </#list>
250         + ")"
251       </#if>
252       ;
253     }
254 
255     @Override
256     public int hashCode() {
257       return java.util.Arrays.deepHashCode(new Object[] {<#list type.fields as field>${field.name}<#if field_has_next>, </#if></#list>});
258     }
259 
260     @Override
261     public boolean equals(Object obj) {
262       if (!(obj instanceof ${name})) {
263         return false;
264       }
265       <#if type.fields?size == 0>
266       return true;
267       <#else>
268       ${type.name} that = (${type.name}) obj;
269       return <#list type.fields as field>Objects.deepEquals(this.${field.name}, that.${field.name}) <#if field_has_next>&&<#else>;</#if>
270       </#list>
271       </#if>
272     }
273 
274     @Override
275     public <T> T accept(ArrowTypeVisitor<T> visitor) {
276       return visitor.visit(this);
277     }
278   }
279   </#list>
280 
281   /**
282    * A user-defined data type that wraps an underlying storage type.
283    */
284   public abstract static class ExtensionType extends ComplexType {
285     /** The on-wire type for this user-defined type. */
286     public abstract ArrowType storageType();
287     /** The name of this user-defined type. Used to identify the type during serialization. */
288     public abstract String extensionName();
289     /** Check equality of this type to another user-defined type. */
290     public abstract boolean extensionEquals(ExtensionType other);
291     /** Save any metadata for this type. */
292     public abstract String serialize();
293     /** Given saved metadata and the underlying storage type, construct a new instance of the user type. */
294     public abstract ArrowType deserialize(ArrowType storageType, String serializedData);
295     /** Construct a vector for the user type. */
296     public abstract FieldVector getNewVector(String name, FieldType fieldType, BufferAllocator allocator);
297 
298     /** The field metadata key storing the name of the extension type. */
299     public static final String EXTENSION_METADATA_KEY_NAME = "ARROW:extension:name";
300     /** The field metadata key storing metadata for the extension type. */
301     public static final String EXTENSION_METADATA_KEY_METADATA = "ARROW:extension:metadata";
302 
303     @Override
304     public ArrowTypeID getTypeID() {
305       return storageType().getTypeID();
306     }
307 
308     @Override
309     public int getType(FlatBufferBuilder builder) {
310       return storageType().getType(builder);
311     }
312 
313     public String toString() {
314       return "ExtensionType(" + extensionName() + ", " + storageType().toString() + ")";
315     }
316 
317     @Override
318     public int hashCode() {
319       return java.util.Arrays.deepHashCode(new Object[] {storageType(), extensionName()});
320     }
321 
322     @Override
323     public boolean equals(Object obj) {
324       if (!(obj instanceof ExtensionType)) {
325         return false;
326       }
327       return this.extensionEquals((ExtensionType) obj);
328     }
329 
330     @Override
331     public <T> T accept(ArrowTypeVisitor<T> visitor) {
332       return visitor.visit(this);
333     }
334   }
335 
336   private static final int defaultDecimalBitWidth = 128;
337 
338   public static org.apache.arrow.vector.types.pojo.ArrowType getTypeForField(org.apache.arrow.flatbuf.Field field) {
339     switch(field.typeType()) {
340     <#list arrowTypes.types as type>
341     <#assign name = type.name?remove_ending("_")>
342     <#assign nameLower = type.name?lower_case>
343     <#assign fields = type.fields>
344     case Type.${type.name}: {
345       org.apache.arrow.flatbuf.${type.name} ${nameLower}Type = (org.apache.arrow.flatbuf.${type.name}) field.type(new org.apache.arrow.flatbuf.${type.name}());
346       <#list type.fields as field>
347       <#if field.type == "int[]">
348       ${field.type} ${field.name} = new int[${nameLower}Type.${field.name}Length()];
349       for (int i = 0; i< ${field.name}.length; ++i) {
350         ${field.name}[i] = ${nameLower}Type.${field.name}(i);
351       }
352       <#else>
353       ${field.type} ${field.name} = ${nameLower}Type.${field.name}();
354       </#if>
355       </#list>
356       <#if type.name == "Decimal">
357       if (bitWidth != defaultDecimalBitWidth && bitWidth != 256) {
358         throw new IllegalArgumentException("Library only supports 128-bit and 256-bit decimal values");
359       }
360       </#if>
361       return new ${name}(<#list type.fields as field><#if field.valueType??>${field.valueType}.fromFlatbufID(${field.name})<#else>${field.name}</#if><#if field_has_next>, </#if></#list>);
362     }
363     </#list>
364     default:
365       throw new UnsupportedOperationException("Unsupported type: " + field.typeType());
366     }
367   }
368 
369   public static Int getInt(org.apache.arrow.flatbuf.Field field) {
370     org.apache.arrow.flatbuf.Int intType = (org.apache.arrow.flatbuf.Int) field.type(new org.apache.arrow.flatbuf.Int());
371     return new Int(intType.bitWidth(), intType.isSigned());
372   }
373 }
374 
375 
376