/** * 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 org.apache.hadoop.hive.serde2.objectinspector; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.hadoop.hive.serde2.objectinspector.primitive.JavaStringObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableBooleanObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableBinaryObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableByteObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableDoubleObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableFloatObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableIntObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableLongObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableShortObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableDateObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.SettableTimestampObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableStringObjectInspector; /** * ObjectInspectorConverters. * */ public final class ObjectInspectorConverters { /** * A converter which will convert objects with one ObjectInspector to another. */ public static interface Converter { Object convert(Object input); } /** * IdentityConverter. * */ public static class IdentityConverter implements Converter { public Object convert(Object input) { return input; } } /** * Returns a converter that converts objects from one OI to another OI. The * returned (converted) object belongs to this converter, so that it can be * reused across different calls. */ public static Converter getConverter(ObjectInspector inputOI, ObjectInspector outputOI) { // If the inputOI is the same as the outputOI, just return an // IdentityConverter. if (inputOI == outputOI) { return new IdentityConverter(); } switch (outputOI.getCategory()) { case PRIMITIVE: switch (((PrimitiveObjectInspector) outputOI).getPrimitiveCategory()) { case BOOLEAN: return new PrimitiveObjectInspectorConverter.BooleanConverter( (PrimitiveObjectInspector) inputOI, (SettableBooleanObjectInspector) outputOI); case BYTE: return new PrimitiveObjectInspectorConverter.ByteConverter( (PrimitiveObjectInspector) inputOI, (SettableByteObjectInspector) outputOI); case SHORT: return new PrimitiveObjectInspectorConverter.ShortConverter( (PrimitiveObjectInspector) inputOI, (SettableShortObjectInspector) outputOI); case INT: return new PrimitiveObjectInspectorConverter.IntConverter( (PrimitiveObjectInspector) inputOI, (SettableIntObjectInspector) outputOI); case LONG: return new PrimitiveObjectInspectorConverter.LongConverter( (PrimitiveObjectInspector) inputOI, (SettableLongObjectInspector) outputOI); case FLOAT: return new PrimitiveObjectInspectorConverter.FloatConverter( (PrimitiveObjectInspector) inputOI, (SettableFloatObjectInspector) outputOI); case DOUBLE: return new PrimitiveObjectInspectorConverter.DoubleConverter( (PrimitiveObjectInspector) inputOI, (SettableDoubleObjectInspector) outputOI); case STRING: if (outputOI instanceof WritableStringObjectInspector) { return new PrimitiveObjectInspectorConverter.TextConverter( (PrimitiveObjectInspector) inputOI); } else if (outputOI instanceof JavaStringObjectInspector) { return new PrimitiveObjectInspectorConverter.StringConverter( (PrimitiveObjectInspector) inputOI); } case DATE: return new PrimitiveObjectInspectorConverter.DateConverter( (PrimitiveObjectInspector) inputOI, (SettableDateObjectInspector) outputOI); case TIMESTAMP: return new PrimitiveObjectInspectorConverter.TimestampConverter( (PrimitiveObjectInspector) inputOI, (SettableTimestampObjectInspector) outputOI); case BINARY: return new PrimitiveObjectInspectorConverter.BinaryConverter( (PrimitiveObjectInspector)inputOI, (SettableBinaryObjectInspector)outputOI); default: throw new RuntimeException("Hive internal error: conversion of " + inputOI.getTypeName() + " to " + outputOI.getTypeName() + " not supported yet."); } case STRUCT: return new StructConverter((StructObjectInspector) inputOI, (SettableStructObjectInspector) outputOI); case LIST: return new ListConverter((ListObjectInspector) inputOI, (SettableListObjectInspector) outputOI); case MAP: return new MapConverter((MapObjectInspector) inputOI, (SettableMapObjectInspector) outputOI); default: throw new RuntimeException("Hive internal error: conversion of " + inputOI.getTypeName() + " to " + outputOI.getTypeName() + " not supported yet."); } } /** * A converter class for List. */ public static class ListConverter implements Converter { ListObjectInspector inputOI; SettableListObjectInspector outputOI; ObjectInspector inputElementOI; ObjectInspector outputElementOI; ArrayList<Converter> elementConverters; Object output; public ListConverter(ListObjectInspector inputOI, SettableListObjectInspector outputOI) { this.inputOI = inputOI; this.outputOI = outputOI; inputElementOI = inputOI.getListElementObjectInspector(); outputElementOI = outputOI.getListElementObjectInspector(); output = outputOI.create(0); elementConverters = new ArrayList<Converter>(); } @Override public Object convert(Object input) { if (input == null) { return null; } // Create enough elementConverters // NOTE: we have to have a separate elementConverter for each element, // because the elementConverters can reuse the internal object. // So it's not safe to use the same elementConverter to convert multiple // elements. int size = inputOI.getListLength(input); while (elementConverters.size() < size) { elementConverters.add(getConverter(inputElementOI, outputElementOI)); } // Convert the elements outputOI.resize(output, size); for (int index = 0; index < size; index++) { Object inputElement = inputOI.getListElement(input, index); Object outputElement = elementConverters.get(index).convert( inputElement); outputOI.set(output, index, outputElement); } return output; } } /** * A converter class for Struct. */ public static class StructConverter implements Converter { StructObjectInspector inputOI; SettableStructObjectInspector outputOI; List<? extends StructField> inputFields; List<? extends StructField> outputFields; ArrayList<Converter> fieldConverters; Object output; public StructConverter(StructObjectInspector inputOI, SettableStructObjectInspector outputOI) { this.inputOI = inputOI; this.outputOI = outputOI; inputFields = inputOI.getAllStructFieldRefs(); outputFields = outputOI.getAllStructFieldRefs(); assert (inputFields.size() == outputFields.size()); fieldConverters = new ArrayList<Converter>(inputFields.size()); for (int f = 0; f < inputFields.size(); f++) { fieldConverters.add(getConverter(inputFields.get(f) .getFieldObjectInspector(), outputFields.get(f) .getFieldObjectInspector())); } output = outputOI.create(); } @Override public Object convert(Object input) { if (input == null) { return null; } // Convert the fields for (int f = 0; f < inputFields.size(); f++) { Object inputFieldValue = inputOI.getStructFieldData(input, inputFields .get(f)); Object outputFieldValue = fieldConverters.get(f).convert( inputFieldValue); outputOI.setStructFieldData(output, outputFields.get(f), outputFieldValue); } return output; } } /** * A converter class for Map. */ public static class MapConverter implements Converter { MapObjectInspector inputOI; SettableMapObjectInspector outputOI; ObjectInspector inputKeyOI; ObjectInspector outputKeyOI; ObjectInspector inputValueOI; ObjectInspector outputValueOI; ArrayList<Converter> keyConverters; ArrayList<Converter> valueConverters; Object output; public MapConverter(MapObjectInspector inputOI, SettableMapObjectInspector outputOI) { this.inputOI = inputOI; this.outputOI = outputOI; inputKeyOI = inputOI.getMapKeyObjectInspector(); outputKeyOI = outputOI.getMapKeyObjectInspector(); inputValueOI = inputOI.getMapValueObjectInspector(); outputValueOI = outputOI.getMapValueObjectInspector(); keyConverters = new ArrayList<Converter>(); valueConverters = new ArrayList<Converter>(); output = outputOI.create(); } @Override public Object convert(Object input) { if (input == null) { return null; } // Create enough keyConverters/valueConverters // NOTE: we have to have a separate key/valueConverter for each key/value, // because the key/valueConverters can reuse the internal object. // So it's not safe to use the same key/valueConverter to convert multiple // key/values. // NOTE: This code tries to get all key-value pairs out of the map. // It's not very efficient. The more efficient way should be to let MapOI // return an Iterator. This is currently not supported by MapOI yet. Map<?, ?> map = inputOI.getMap(input); int size = map.size(); while (keyConverters.size() < size) { keyConverters.add(getConverter(inputKeyOI, outputKeyOI)); valueConverters.add(getConverter(inputValueOI, outputValueOI)); } // CLear the output outputOI.clear(output); // Convert the key/value pairs int entryID = 0; for (Map.Entry<?, ?> entry : map.entrySet()) { Object inputKey = entry.getKey(); Object inputValue = entry.getValue(); Object outputKey = keyConverters.get(entryID).convert(inputKey); Object outputValue = valueConverters.get(entryID).convert(inputValue); entryID++; outputOI.put(output, outputKey, outputValue); } return output; } } private ObjectInspectorConverters() { // prevent instantiation } }