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

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

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

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static net.gdface.thrift.TypeTransformer.getInstance;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.concurrent.Immutable;

import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.microsoft.thrifty.Struct;
import com.microsoft.thrifty.StructBuilder;

@Immutable
public class ThriftyStructMetadata {
    public static final LoadingCache,ThriftyStructMetadata> 
	STRUCTS_CACHE = 
		CacheBuilder.newBuilder().build(
				new CacheLoader,ThriftyStructMetadata>(){
					@Override
					public ThriftyStructMetadata load(Class key) throws Exception {
						return new ThriftyStructMetadata(key);
					}});
	private final Class structType;
	/** 字段ID对应的字段对象 */
	private final ImmutableMap fields;
	/** builder对象所有字段的set方法 */
	private final ImmutableMap buildSetters;
	private final Class> builderClass;
	private final Method buildMethod;
	@SuppressWarnings("unchecked")
	private ThriftyStructMetadata(Class structType ) {
		this.structType = checkNotNull(structType,"struct is null");
		checkArgument(Struct.class.isAssignableFrom(structType),
				"structType %s not immplement the %s",structType.getName(),Struct.class.getName());
		try {
			String className = structType.getName() + "$Builder";
			builderClass = (Class>) Class.forName(className);
		} catch (Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);       
        } 
		ImmutableMap.Builder fieldBuilder = ImmutableMap.builder();
		ImmutableMap.Builder methodBuilder = ImmutableMap.builder();

		for(Field field:structType.getDeclaredFields()){
			if((field.getModifiers() & Modifier.STATIC)==0){
				fieldBuilder.put(field.getName(), field);
				try {
					Method method = builderClass.getMethod(field.getName(), field.getType());
					methodBuilder.put(field.getName(), method);
				} catch (NoSuchMethodException e) {
					throw new RuntimeException(e);
				} 
			} 
		}
		fields = fieldBuilder.build();
		buildSetters = methodBuilder.build();
		
		try {
			buildMethod = builderClass.getDeclaredMethod("build");
		} catch (Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);       
        } 
	}
	public ImmutableMap getFields() {
		return fields;
	}
	public Class getStructType() {
		return structType;
	}
	@SuppressWarnings("unchecked")
	public void setValue(Object instance,short id,L value){
		checkNotNull(instance,"instance is null");
		checkArgument(structType.isInstance(instance),"invalid value type,required %s",structType.getName());
		Field field = fields.get(id);
		checkNotNull(field,"invalid field id=%s for %s",Short.toString(id),structType.getName());
		Class fieldType = field.getType();
		try {
			field.setAccessible(true);
			if(value == null){
				checkArgument(!fieldType.isPrimitive(),
						"primitive field %s of %s required not null value",field.getName(),structType.getName());
				field.set(instance,null);
			}
			else{
				field.set(instance, getInstance().to(value, (Class) value.getClass(), fieldType));
			}
		} catch (Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        } 
	}
	@SuppressWarnings("unchecked")
	private V getValue(Object instance,String name){
		checkArgument(structType.isInstance(instance),"invalid value type,required %s",structType.getName());

		Field field = fields.get(name);
		checkNotNull(field,"invalid field name=%s for %s",name,structType.getName());
		try {
			return (V) field.get(instance);
		} catch (Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);       
        } 
	}

	/**
	 * 根据字段值构造实例
	 * @param fieldValues
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T constructStruct(Map fieldValues){
		checkNotNull(fieldValues,"fieldValues is null");
		try {
			// new Builder()
			StructBuilder builder = (StructBuilder) builderClass.newInstance();
			for(Entry entry : fieldValues.entrySet()){
				Method method = buildSetters.get(entry.getKey());
				checkNotNull(method,"method is null");
				TypeValue typeValue= entry.getValue();
				// 调用Builder的设置方法设置字段值
				method.invoke(builder, getInstance().cast(
						typeValue.value,
						typeValue.type,
						fields.get(entry.getKey()).getGenericType()));
			}
			// build()
			return (T) buildMethod.invoke(builder);
		} catch (InvocationTargetException e){
			Throwables.throwIfUnchecked(e.getCause());
            throw new RuntimeException(e.getCause());  
		}catch (Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);       
        }
	}
	/**
	 * 从 {@link com.microsoft.thrifty.Struct} 实例中返回所有字段值
	 * @param instance
	 * @return
	 */
	Map getFieldValues(Object instance){
		checkNotNull(instance,"instance is null");
		checkArgument(structType.isInstance(instance),"invalid value type,required %s",structType.getName());
		ImmutableMap.Builder builder = ImmutableMap.builder();
		for(Entry entry:fields.entrySet()){
			String name = entry.getKey();
			Field field = entry.getValue();
			builder.put(name, new TypeValue(field.getType(), getValue(instance, name)));
		}		
		return builder.build();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy