org.apache.hadoop.hive.ql.udf.generic.GenericUDFReflect2 Maven / Gradle / Ivy
/*
* 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.ql.udf.generic;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import org.apache.hadoop.hive.common.type.HiveDecimal;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.UDFType;
import org.apache.hadoop.hive.serde2.io.ByteWritable;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
import org.apache.hadoop.hive.serde2.io.ShortWritable;
import org.apache.hadoop.hive.serde2.io.TimestampWritable;
import org.apache.hadoop.hive.serde2.objectinspector.ConstantObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.PrimitiveTypeEntry;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
/**
* A simple generic udf to call java functions via reflection.
*/
@Description(name = "reflect2",
value = "_FUNC_(arg0,method[,arg1[,arg2..]]) calls method of arg0 with reflection",
extended = "Use this UDF to call Java methods by matching the argument signature\n")
@UDFType(deterministic = true)
public class GenericUDFReflect2 extends AbstractGenericUDFReflect {
private PrimitiveObjectInspector targetOI;
private PrimitiveObjectInspector returnOI;
private transient Method method;
private transient Writable returnObj;
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if (arguments.length < 2) {
throw new UDFArgumentLengthException(
"The function GenericUDFReflect2(arg0,method[,arg1[,arg2]...])"
+ " accepts 2 or more arguments.");
}
if (arguments[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentTypeException(1, "The target instance should be a primitive type.");
}
targetOI = (PrimitiveObjectInspector) arguments[0];
if (!(arguments[1] instanceof StringObjectInspector)) {
throw new UDFArgumentTypeException(1, "The method name should be string type.");
}
if (!(arguments[1] instanceof ConstantObjectInspector)) {
throw new UDFArgumentTypeException(1, "The method name should be a constant.");
}
Text methodName = (Text) ((ConstantObjectInspector)arguments[1]).getWritableConstantValue();
if (methodName.toString().equals("hashCode") && arguments.length == 2) {
// it's non-deterministic
throw new UDFArgumentTypeException(1, "Use hash() UDF instead of this.");
}
setupParameterOIs(arguments, 2);
Class> targetClass = PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveCategory(
targetOI.getPrimitiveCategory()).primitiveJavaClass;
try {
method = findMethod(targetClass, methodName.toString(), null, true);
// Note: type param is not available here.
PrimitiveTypeEntry typeEntry = getTypeFor(method.getReturnType());
returnOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
typeEntry.primitiveCategory);
returnObj = (Writable) returnOI.getPrimitiveWritableClass().newInstance();
} catch (Exception e) {
throw new UDFArgumentException(e);
}
return returnOI;
}
private PrimitiveObjectInspectorUtils.PrimitiveTypeEntry getTypeFor(Class> retType)
throws UDFArgumentException {
PrimitiveObjectInspectorUtils.PrimitiveTypeEntry entry =
PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveJavaType(retType);
if (entry == null) {
entry = PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveJavaClass(retType);
}
if (entry == null) {
throw new UDFArgumentException("Invalid return type " + retType);
}
return entry;
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
Object targetObject = targetOI.getPrimitiveJavaObject(arguments[0].get());
if (targetObject == null) {
return null;
}
Object result = null;
try {
result = method.invoke(targetObject, setupParameters(arguments, 2));
} catch (InvocationTargetException e) {
throw new HiveException(e.getCause());
} catch (Exception e) {
throw new HiveException(e);
}
if (result == null) {
return null;
}
switch (returnOI.getPrimitiveCategory()) {
case VOID:
return null;
case BOOLEAN:
((BooleanWritable)returnObj).set((Boolean)result);
return returnObj;
case BYTE:
((ByteWritable)returnObj).set((Byte)result);
return returnObj;
case SHORT:
((ShortWritable)returnObj).set((Short)result);
return returnObj;
case INT:
((IntWritable)returnObj).set((Integer)result);
return returnObj;
case LONG:
((LongWritable)returnObj).set((Long)result);
return returnObj;
case FLOAT:
((FloatWritable)returnObj).set((Float)result);
return returnObj;
case DOUBLE:
((DoubleWritable)returnObj).set((Double)result);
return returnObj;
case STRING:
((Text)returnObj).set((String)result);
return returnObj;
case TIMESTAMP:
((TimestampWritable)returnObj).set((Timestamp)result);
return returnObj;
case BINARY:
((BytesWritable)returnObj).set((byte[])result, 0, ((byte[]) result).length);
return returnObj;
case DECIMAL:
((HiveDecimalWritable)returnObj).set((HiveDecimal)result);
return returnObj;
}
throw new HiveException("Invalid type " + returnOI.getPrimitiveCategory());
}
@Override
protected String functionName() {
return "reflect2";
}
}