com.netease.arctic.log.JsonToLogDataConverters Maven / Gradle / Ivy
The newest version!
/*
* 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.
*/
package com.netease.arctic.log;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.netease.arctic.log.data.LogArrayData;
import com.netease.arctic.log.data.LogMapData;
import com.netease.arctic.shade.org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import com.netease.arctic.shade.org.apache.iceberg.types.Type;
import com.netease.arctic.shade.org.apache.iceberg.types.Types;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.netease.arctic.log.TimeFormats.ISO8601_TIMESTAMP_WITH_LOCAL_TIMEZONE_FORMAT;
import static com.netease.arctic.log.TimeFormats.SQL_TIMESTAMP_FORMAT;
import static com.netease.arctic.log.TimeFormats.SQL_TIME_FORMAT;
import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
/**
* Tool class used to convert from {@link JsonNode} to {@link LogData}.
* {@link T} indicate an actual value wrapped within {@link LogData}
*/
public class JsonToLogDataConverters implements Serializable {
private static final long serialVersionUID = 647419880134661188L;
private final boolean failOnMissingField = false;
LogData.Factory factory;
LogArrayData.Factory arrayFactory;
LogMapData.Factory mapFactory;
public JsonToLogDataConverters(
LogData.Factory factory,
LogArrayData.Factory arrayFactory,
LogMapData.Factory mapFactory) {
this.factory = Preconditions.checkNotNull(factory);
this.arrayFactory = Preconditions.checkNotNull(arrayFactory);
this.mapFactory = Preconditions.checkNotNull(mapFactory);
}
/**
* Converter to convert {@link JsonNode} to log data.
*
* @param to indicate the log data type
*/
interface JsonToLogDataConverter extends Converter {
}
public JsonToLogDataConverter createConverter(Type type) {
return wrapIntoNullableConverter(createNotNullConverter(type));
}
private JsonToLogDataConverter createNotNullConverter(Type type) {
switch (type.typeId()) {
case BOOLEAN:
return this::convertToBoolean;
case INTEGER:
return this::convertToInt;
case LONG:
return this::convertToLong;
case FLOAT:
return this::convertToFloat;
case DOUBLE:
return this::convertToDouble;
case DATE:
return this::convertToDate;
case TIME:
// For the type: Flink only support TimeType with default precision (second) now. The precision of time is
// not supported in Flink, so we can think of it as a simple time type directly.
// For the data: Flink uses int that support mills to represent time data, so it supports mills precision.
return this::convertToTime;
case TIMESTAMP:
Types.TimestampType timestamp = (Types.TimestampType) type;
if (timestamp.shouldAdjustToUTC()) {
return this::convertToTimestampWithLocalZone;
} else {
return this::convertToTimestamp;
}
case STRING:
return this::convertToString;
case UUID:
case FIXED:
case BINARY:
return this::convertToBytes;
case DECIMAL:
return this::convertDecimal;
case LIST:
return createListConverter(type);
case MAP:
return createMapConverter(type);
case STRUCT:
return createStructConverter(type);
default:
throw new UnsupportedOperationException("Not Support to parse type: " + type);
}
}
private JsonToLogDataConverter createStructConverter(Type type) {
final List fields = type.asNestedType().asStructType().fields();
final Type[] fieldTypes = fields.stream()
.map(Types.NestedField::type)
.toArray(Type[]::new);
final String[] fieldNames = fields.stream()
.map(Types.NestedField::name).toArray(String[]::new);
final List> fieldConverters =
Arrays.stream(fieldTypes)
.map(this::createConverter)
.collect(Collectors.toList());
return (jsonNode, context) -> {
ObjectNode node = (ObjectNode) jsonNode;
int arity = fieldNames.length;
Object[] struct = new Object[arity];
for (int i = 0; i < arity; i++) {
String fieldName = fieldNames[i];
JsonNode field = node.get(fieldName);
Object convertedField = convertField(fieldConverters.get(i), fieldName, field, context);
struct[i] = convertedField;
}
return factory.createActualValue(struct, fieldTypes);
};
}
private JsonToLogDataConverter createMapConverter(Type type) {
Types.MapType map = type.asNestedType().asMapType();
Types.NestedField keyField = map.field(map.keyId());
Types.NestedField valueField = map.field(map.valueId());
final JsonToLogDataConverter keyConverter = createConverter(keyField.type());
final JsonToLogDataConverter valueConverter = createConverter(valueField.type());
return (jsonNode, context) -> {
Iterator> fields = jsonNode.fields();
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy