Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.vector.complex.MapVector;
import org.apache.arrow.vector.complex.impl.UnionMapWriter;
import org.apache.arrow.vector.util.ObjectMapperFactory;

/**
* Consumer which consume map type values from {@link ResultSet}. Write the data into {@link
Expand All @@ -36,7 +35,7 @@
public class MapConsumer extends BaseConsumer<MapVector> {

private final UnionMapWriter writer;
private final ObjectMapper objectMapper = ObjectMapperFactory.newObjectMapper();
private final ObjectMapper objectMapper = new ObjectMapper();
private final TypeReference<Map<String, String>> typeReference =
new TypeReference<Map<String, String>>() {};
private int currentRow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.arrow.vector.util.JsonStringArrayList;
import org.apache.arrow.vector.util.JsonStringHashMap;
import org.apache.arrow.vector.util.ObjectMapperFactory;
import org.apache.arrow.vector.util.Text;

/**
Expand Down Expand Up @@ -295,7 +294,7 @@ public static void assertMapVectorValues(
public static Map<String, String>[] getMapValues(String[] values, String dataType) {
String[] dataArr = getValues(values, dataType);
Map<String, String>[] maps = new Map[dataArr.length];
ObjectMapper objectMapper = ObjectMapperFactory.newObjectMapper();
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<Map<String, String>> typeReference = new TypeReference<Map<String, String>>() {};
for (int idx = 0; idx < dataArr.length; idx++) {
String jsonString = dataArr[idx].replace("|", ",");
Expand Down
17 changes: 0 additions & 17 deletions vector/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,6 @@ under the License.
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-memory-netty</artifactId>
Expand Down
95 changes: 72 additions & 23 deletions vector/src/main/codegen/templates/ArrowType.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

import com.google.flatbuffers.FlatBufferBuilder;

import java.io.IOException;
import java.util.Locale;
import java.util.Objects;

import org.apache.arrow.flatbuf.Type;
Expand All @@ -32,25 +34,12 @@
import org.apache.arrow.vector.FieldVector;
import org.apache.arrow.vector.ValueVector;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;

/**
* Arrow types
* Source code generated using FreeMarker template ${.template_name}
**/
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "name")
@JsonSubTypes({
<#list arrowTypes.types as type>
@JsonSubTypes.Type(value = ArrowType.${type.name?remove_ending("_")}.class, name = "${type.name?remove_ending("_")?lower_case}"),
</#list>
})
public abstract class ArrowType {

public static abstract class PrimitiveType extends ArrowType {
Expand Down Expand Up @@ -93,13 +82,48 @@ private ArrowTypeID(byte flatbufType) {
}
}

@JsonIgnore
public abstract ArrowTypeID getTypeID();
@JsonIgnore
public abstract boolean isComplex();
public abstract int getType(FlatBufferBuilder builder);
public abstract <T> T accept(ArrowTypeVisitor<T> visitor);

/** The lower-case type name used as the JSON discriminator for this type. */
String getNameAsString() {
return getTypeID().name().toLowerCase(Locale.ROOT);
}

/** Serializes this type to JSON, as a {@code {"name": ..., ...}} object. */
void writeJson(JsonGenerator generator) throws IOException {
generator.writeStartObject();
generator.writeStringField("name", getNameAsString());
writeJsonFields(generator);
generator.writeEndObject();
}

/** Writes the type-specific fields (everything except the discriminator) to JSON. */
void writeJsonFields(JsonGenerator generator) throws IOException {
}

/** Constructs an ArrowType from its JSON discriminator name and parsed fields. */
static ArrowType getArrowType(String name, java.util.Map<String, Object> fields) {
switch (name) {
<#list arrowTypes.types as type>
<#assign typeName = type.name?remove_ending("_")>
case "${type.name?remove_ending("_")?lower_case}":
<#if type.name == "Decimal">
return new Decimal(
JsonValues.asInt(fields.get("precision")),
JsonValues.asInt(fields.get("scale")),
fields.get("bitWidth") == null ? 128 : JsonValues.asInt(fields.get("bitWidth")));
<#else>
return new ${typeName}(<#list type.fields as field><#if field.valueType??>JsonValues.parseEnum(${field.valueType}.class, fields.get("${field.name}"))<#elseif field.type == "int">JsonValues.asInt(fields.get("${field.name}"))<#elseif field.type == "boolean">JsonValues.asBoolean(fields.get("${field.name}"))<#elseif field.type == "int[]">JsonValues.asIntArray(fields.get("${field.name}"))<#else>JsonValues.asString(fields.get("${field.name}"))</#if><#if field_has_next>, </#if></#list>);
</#if>
</#list>
default:
throw new IllegalArgumentException("Unknown type: " + name);
}
}

/**
* to visit the ArrowTypes
* <code>
Expand Down Expand Up @@ -170,11 +194,10 @@ public static class ${name} extends <#if type.complex>ComplexType<#else>Primitiv

<#if type.name == "Decimal">
// Needed to support golden file integration tests.
@JsonCreator
public static Decimal createDecimal(
@JsonProperty("precision") int precision,
@JsonProperty("scale") int scale,
@JsonProperty("bitWidth") Integer bitWidth) {
int precision,
int scale,
Integer bitWidth) {

return new Decimal(precision, scale, bitWidth == null ? 128 : bitWidth);
}
Expand All @@ -192,13 +215,11 @@ public Decimal(int precision, int scale) {
this(precision, scale, 128);
}

<#else>
@JsonCreator
</#if>
public ${type.name}(
<#list type.fields as field>
<#assign fieldType = field.valueType!field.type>
@JsonProperty("${field.name}") ${fieldType} ${field.name}<#if field_has_next>, </#if>
${fieldType} ${field.name}<#if field_has_next>, </#if>
</#list>
) {
<#list type.fields as field>
Expand All @@ -212,6 +233,29 @@ public Decimal(int precision, int scale) {
return ${field.name};
}
</#list>

@Override
void writeJsonFields(JsonGenerator generator) throws IOException {
<#list type.fields as field>
<#if field.valueType??>
generator.writeStringField("${field.name}", ${field.name} == null ? null : ${field.name}.name());
<#elseif field.type == "int">
generator.writeNumberField("${field.name}", ${field.name});
<#elseif field.type == "boolean">
generator.writeBooleanField("${field.name}", ${field.name});
<#elseif field.type == "int[]">
generator.writeArrayFieldStart("${field.name}");
if (${field.name} != null) {
for (int value : ${field.name}) {
generator.writeNumber(value);
}
}
generator.writeEndArray();
<#else>
generator.writeStringField("${field.name}", ${field.name});
</#if>
</#list>
}
</#if>

@Override
Expand Down Expand Up @@ -312,6 +356,11 @@ public int getType(FlatBufferBuilder builder) {
return storageType().getType(builder);
}

@Override
void writeJson(JsonGenerator generator) throws IOException {
storageType().writeJson(generator);
}

public String toString() {
return "ExtensionType(" + extensionName() + ", " + storageType().toString() + ")";
}
Expand Down
7 changes: 0 additions & 7 deletions vector/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,11 @@
exports org.apache.arrow.vector.util;
exports org.apache.arrow.vector.validate;

opens org.apache.arrow.vector.types.pojo to
com.fasterxml.jackson.databind;

requires com.fasterxml.jackson.annotation;
requires com.fasterxml.jackson.core;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
requires flatbuffers.java;
requires jdk.unsupported;
requires org.apache.arrow.format;
requires org.apache.arrow.memory.core;
requires org.apache.commons.codec;
requires org.slf4j;

uses org.apache.arrow.vector.compression.CompressionCodec.Factory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
*/
package org.apache.arrow.vector.extension;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -72,6 +74,7 @@
*/
public class OpaqueType extends ArrowType.ExtensionType {
private static final AtomicBoolean registered = new AtomicBoolean(false);
private static final JsonFactory JSON_FACTORY = new JsonFactory();
public static final String EXTENSION_NAME = "arrow.opaque";
private final ArrowType storageType;
private final String typeName;
Expand Down Expand Up @@ -128,41 +131,85 @@ public boolean extensionEquals(ExtensionType other) {

@Override
public String serialize() {
ObjectMapper mapper = new ObjectMapper();
ObjectNode object = mapper.createObjectNode();
object.put("type_name", typeName);
object.put("vendor_name", vendorName);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
try (StringWriter writer = new StringWriter();
JsonGenerator generator = JSON_FACTORY.createGenerator(writer)) {
generator.writeStartObject();
generator.writeStringField("type_name", typeName);
generator.writeStringField("vendor_name", vendorName);
generator.writeEndObject();
generator.flush();
return writer.toString();
} catch (IOException e) {
throw new RuntimeException("Could not serialize " + this, e);
}
}

@Override
public ArrowType deserialize(ArrowType storageType, String serializedData) {
ObjectMapper mapper = new ObjectMapper();
JsonNode object;
java.util.Map<String, Object> object;
try {
object = mapper.readTree(serializedData);
} catch (JsonProcessingException e) {
object = parseObject(serializedData);
} catch (IOException e) {
throw new InvalidExtensionMetadataException("Extension metadata is invalid", e);
}
JsonNode typeName = object.get("type_name");
JsonNode vendorName = object.get("vendor_name");
if (typeName == null) {
if (object == null) {
throw new InvalidExtensionMetadataException("Extension metadata is invalid");
}
if (!object.containsKey("type_name")) {
throw new InvalidExtensionMetadataException("typeName is missing");
}
if (vendorName == null) {
if (!object.containsKey("vendor_name")) {
throw new InvalidExtensionMetadataException("vendorName is missing");
}
if (!typeName.isTextual()) {
Object typeName = object.get("type_name");
Object vendorName = object.get("vendor_name");
if (!(typeName instanceof String)) {
throw new InvalidExtensionMetadataException("typeName should be string, was " + typeName);
}
if (!vendorName.isTextual()) {
if (!(vendorName instanceof String)) {
throw new InvalidExtensionMetadataException("vendorName should be string, was " + vendorName);
}
return new OpaqueType(storageType, typeName.asText(), vendorName.asText());
return new OpaqueType(storageType, (String) typeName, (String) vendorName);
}

/** Parses a JSON object into a generic map, or returns null if the root is not an object. */
private static java.util.Map<String, Object> parseObject(String serializedData)
throws IOException {
try (JsonParser parser = JSON_FACTORY.createParser(serializedData)) {
if (parser.nextToken() != JsonToken.START_OBJECT) {
return null;
}
java.util.Map<String, Object> result = new java.util.LinkedHashMap<>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
String name = parser.currentName();
result.put(name, readScalarOrSkip(parser));
}
return result;
}
}

private static Object readScalarOrSkip(JsonParser parser) throws IOException {
JsonToken token = parser.nextToken();
switch (token) {
case VALUE_STRING:
return parser.getValueAsString();
case VALUE_NUMBER_INT:
return parser.getLongValue();
case VALUE_NUMBER_FLOAT:
return parser.getDoubleValue();
case VALUE_TRUE:
return Boolean.TRUE;
case VALUE_FALSE:
return Boolean.FALSE;
case VALUE_NULL:
return null;
case START_OBJECT:
case START_ARRAY:
parser.skipChildren();
return new Object();
default:
return null;
}
}

@Override
Expand Down
Loading
Loading