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<Type>() { 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