All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.gdface.thrift.ThriftUtils Maven / Gradle / Ivy

There is a newer version: 2.10.3
Show newest version
package net.gdface.thrift;

import static com.facebook.swift.codec.metadata.FieldKind.THRIFT_FIELD;
import static com.google.common.base.Preconditions.*;
import static java.lang.String.format;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;

import com.facebook.swift.codec.ThriftField.Requiredness;
import com.facebook.swift.codec.ThriftStruct;
import com.facebook.swift.codec.metadata.ThriftCatalog;
import com.facebook.swift.codec.metadata.ThriftCatalogWithTransformer;
import com.facebook.swift.codec.metadata.ThriftConstructorInjection;
import com.facebook.swift.codec.metadata.ThriftExtraction;
import com.facebook.swift.codec.metadata.ThriftFieldExtractor;
import com.facebook.swift.codec.metadata.ThriftFieldInjection;
import com.facebook.swift.codec.metadata.ThriftFieldMetadata;
import com.facebook.swift.codec.metadata.ThriftInjection;
import com.facebook.swift.codec.metadata.ThriftMethodExtractor;
import com.facebook.swift.codec.metadata.ThriftMethodInjection;
import com.facebook.swift.codec.metadata.ThriftParameterInjection;
import com.facebook.swift.codec.metadata.ThriftStructMetadata;
import com.google.common.base.Throwables;
import com.google.common.reflect.TypeToken;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.microsoft.thrifty.Struct;
import com.microsoft.thrifty.ThriftException;

/**
 * thrift工具
 * @author guyadong
 *
 */
public class ThriftUtils {
	public static final ThriftCatalog CATALOG = new ThriftCatalogWithTransformer();
	public static final String DECORATOR_PKG_SUFFIX="decorator";
	public static final String CLIENT_SUFFIX="client";
	public static final String DECORATOR_CLIENT_PKG_SUFFIX= DECORATOR_PKG_SUFFIX + "." + CLIENT_SUFFIX;
	public ThriftUtils() {
	}

	/**
	 * 构造{@code metadata}指定类型的实例并填充字段
	 * 参见 {@link com.facebook.swift.codec.internal.reflection.ReflectionThriftStructCodec#constructStruct(Map)}
	 * @param data
	 * @param metadata
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static T constructStruct(Map data,ThriftStructMetadata metadata) 
		throws Exception{
		T instance;
	    {
	        ThriftConstructorInjection constructor = metadata.getConstructorInjection().get();
	        Type[] dstTypes = constructor.getConstructor().getGenericParameterTypes();
	        Type[] srcTypes = new Type[constructor.getParameters().size()];
	        Object[] parametersValues = new Object[constructor.getParameters().size()];
	        checkState(dstTypes.length == parametersValues.length);
	        for (ThriftParameterInjection parameter : constructor.getParameters()) {
	        	TypeValue value = data.get(parameter.getId());
	            parametersValues[parameter.getParameterIndex()] = value.value;
	            srcTypes[parameter.getParameterIndex()] = value.type;
	        }
	        for(int i =0;i
	 * 参见 {@link com.facebook.swift.codec.internal.reflection.ReflectionThriftStructCodec#constructStruct(Map)}
	 * @param data
	 * @param metadata
	 * @param instance
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static T fillStructField(Map data,ThriftStructMetadata metadata,T instance) 
		throws Exception{
		checkArgument(null != instance,"instance is null");
		// inject fields
	    for (ThriftFieldMetadata fieldMetadata : metadata.getFields(THRIFT_FIELD)) {
	        for (ThriftInjection injection : fieldMetadata.getInjections()) {
	            if (injection instanceof ThriftFieldInjection) {
	                ThriftFieldInjection fieldInjection = (ThriftFieldInjection) injection;	                
	                TypeValue value = data.get(fieldInjection.getName());
	                if (value != null) {
	                	Field f = fieldInjection.getField();
	                    f.set(instance, TypeTransformer.getInstance().cast(value.value,value.type,f.getGenericType()));
	                }
	            }
	        }
	    }
	
	    // inject methods
	    for (ThriftMethodInjection methodInjection : metadata.getMethodInjections()) {
	        boolean shouldInvoke = false;
	        Object[] parametersValues = new Object[methodInjection.getParameters().size()];
	        Type[] srcTypes = new Type[methodInjection.getParameters().size()];
	        for (ThriftParameterInjection parameter : methodInjection.getParameters()) {
	        	TypeValue value = data.get(parameter.getName());
	            if (value != null) {
	                parametersValues[parameter.getParameterIndex()] = value.value;
	                srcTypes[parameter.getParameterIndex()] = value.type;
	                shouldInvoke = true;
	            }
	        }
	
	        if (shouldInvoke) {
	            try {	            	
	            	Method method = methodInjection.getMethod();
	            	Type[] parameterTypes = method.getGenericParameterTypes();
	            	for(int i = 0 ;i
	 * 
	 * @param instance
	 * @param field
	 * @return
	 * @throws Exception
	 * @see {@link com.facebook.swift.codec.internal.reflection.AbstractReflectionThriftCodec#getFieldValue(Object, ThriftFieldMetadata)}
	 */
	public static TypeValue getFieldValue(Object instance, ThriftFieldMetadata field) throws Exception {
		try {
			if (field.getExtraction().isPresent()) {
				ThriftExtraction extraction = field.getExtraction().get();
				if (extraction instanceof ThriftFieldExtractor) {
					ThriftFieldExtractor thriftFieldExtractor = (ThriftFieldExtractor) extraction;
					Field f = thriftFieldExtractor.getField();
					return new TypeValue(f.getGenericType(),f.get(instance));
				} else if (extraction instanceof ThriftMethodExtractor) {
					ThriftMethodExtractor thriftMethodExtractor = (ThriftMethodExtractor) extraction;
					Method method = thriftMethodExtractor.getMethod();
					return new TypeValue(method.getGenericReturnType(),method.invoke(instance));
				}
				throw new IllegalAccessException("Unsupported field extractor type " + extraction.getClass().getName());
			}
			throw new IllegalAccessException("No extraction present for " + field);
		} catch (InvocationTargetException e) {
			if (e.getTargetException() != null) {
				Throwables.throwIfInstanceOf(e.getTargetException(), Exception.class);
			}
			throw e;
		}
	}

	/**
	 * 根据{@code metadata}类型数据获取{@code instance}实例所有的字段值
	 * 参见 {@link com.facebook.swift.codec.internal.reflection.ReflectionThriftStructCodec#write(Object, org.apache.thrift.protocol.TProtocol)}
	 * @param instance
	 * @param metadata
	 * @return 字段值映射表
	 */
	public static Map getFieldValues(Object instance, ThriftStructMetadata metadata) {
		checkArgument(null != instance && null != metadata && metadata.getStructClass().isInstance(instance), 
				"instance,metadata must not be null");
		
		Collection fields = metadata.getFields(THRIFT_FIELD);
		Map data = new HashMap<>(fields.size());
		for (ThriftFieldMetadata field : fields) {
			try {
	            // is the field readable?
	            if (field.isWriteOnly()) {
	                continue;
	            }
				TypeValue value = getFieldValue(instance, field);
				if (value.value == null) {
					if (field.getRequiredness() == Requiredness.REQUIRED) {
						throw new RuntimeException("required field was not set");
					} else {
						continue;
					}
				}
				data.put(field.getName(), value);
			} catch (Exception e) {
				Throwables.throwIfUnchecked(e);
				throw new RuntimeException(e);
			}
		}
		return data;
	}

	public static boolean isThriftStruct(Type type){
		return type instanceof Class 
			? ((Class)type).isAnnotationPresent(ThriftStruct.class) 
			: false;
	}
	public static boolean isThriftyStruct(Type type){
		return type instanceof Class 
			? Struct.class.isAssignableFrom((Class)type)
			: false;
	}
	public static boolean isThriftDecorator(Type type){
		return type instanceof Class 
				? ThriftDecorator.class.isAssignableFrom((Class)type) 
				: false;
	}

	public static boolean isPrimitiveArray(Type type){
		if(type instanceof Class){
			Class clazz = (Class)type;
			return clazz.isArray() && clazz.getComponentType().isPrimitive();
		}
		return false;
	}

	public static boolean isPrimitivefloat(Type type){
		return type == float.class;
	}

	public static boolean isException(Type type){
		return null == type 
				? false 
				: Exception.class.isAssignableFrom(TypeToken.of(type).getRawType());
	}
	public static boolean isThriftException(Type type){
		return isException(type) && isThriftStruct(type);
	}
	public static boolean isThriftyException(Type type){
		return isException(type) && isThriftyStruct(type);
	}
	/**
	 * 返回{@code clazz}对应的装饰类
	 * @param clazz
	 * @return 如果没有装饰类则返回{@code null}
	 */
	@SuppressWarnings("unchecked")
	public static >Class getDecoratorType(Class clazz){
		if(!isThriftStruct(clazz)){
			String decoratorClazzName = clazz.getPackage().getName() 
					+ "."
					+ DECORATOR_CLIENT_PKG_SUFFIX 
					+ "." 
					+ clazz.getSimpleName();
			try {
				Class decoratorClazz = Class.forName(decoratorClazzName);
				checkState(isThriftDecoratorPair(decoratorClazz,clazz),
						"%s must immplement %s",
						decoratorClazz.getName(),
						ThriftDecorator.class.getName());
				return (Class) decoratorClazz;
			} catch (ClassNotFoundException e) {
			}
		}
		return null;
	}

	/**
	 * 判断 {@code left & right}之间是否为装饰类和被装饰类关系
	 * @param left 装饰类
	 * @param right 补装饰类
	 * @return
	 */
	public static boolean isThriftDecoratorPair(Classleft,Classright){
		try {
			return isThriftDecorator(left) 
					&& left.getMethod("delegate").getReturnType() == right;
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 判断 {@code right}是否为{@code left}对应的client端存根类型
	 * @param left
	 * @param right
	 * @return
	 */
	public static boolean isThriftClientPair(Classleft,Classright){
		return getMiddleClass(left,right)!=null;
	}
	/**
	 * 返回 {@code left & right}之间的decorator类型
	 * @param left 原始类型
	 * @param right {@code left}对应的client端存根类型
	 * @return
	 */
	public static ,R>Class getMiddleClass(Classleft,Classright){
		if(isThriftyStruct(right)){
			Class decoratorClass = getDecoratorType(left);
			if(null != decoratorClass && decoratorClass.getSimpleName().equals(left.getSimpleName())){
				return decoratorClass;
			}			
		}
		return null;
	}
	/**
	 * @param left
	 * @param right
	 * @return
	 * @see #getMiddleClass(Class, Class)
	 */
	@SuppressWarnings("unchecked")
	public static ,R>Class getMiddleClassChecked(Classleft,Classright){
		return (Class) checkNotNull(
						getMiddleClass(left,right),
						"NOT FOUND decorator class for %s",
						left.getName());
	}
	/** 避免{@code null}抛出异常 */
	public static  T returnNull(ThriftException e){
		if(e.kind == ThriftException.Kind.MISSING_RESULT  ){
            return null;
        }
	    throw e;
	}
	/** 避免{@code null}抛出异常 
	 * @throws Throwable */
	public static  T returnNull(Throwable e) throws Throwable{
		if(e instanceof ThriftException){
			return returnNull((ThriftException)e);
		}
	    throw e;
	}
	public static void addCallback(
			final ListenableFuture future,
			final FutureCallback callback,Executor executor) {
		checkArgument(null != callback,"callback is null");
		checkArgument(null != executor,"executor is null");
		Runnable callbackListener =
				new Runnable() {
			@Override
			public void run() {
				V value;
				try {
					value = Futures.getDone(future);
				} catch (ExecutionException e) {
					try{
						// value is null
						value = returnNull(e.getCause()); 
					}catch(Throwable t){
						callback.onFailure(t);
						return;
					}                    
				} catch (Throwable e) {
					callback.onFailure(e);
					return;
				}
				callback.onSuccess(value);
			}
		};
		future.addListener(callbackListener, executor);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy