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

rpc.turbo.param.MethodParamClassFactory Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
package rpc.turbo.param;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.common.hash.Hashing;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import rpc.turbo.util.concurrent.ThreadLocalStringBuilder;

public final class MethodParamClassFactory {

	private static final String NOT_SUPPORT_PARAMETER_NAME_MSG = "must turn on \"Store information about method parameters (usable via reflection)\", see https://www.concretepage.com/java/jdk-8/java-8-reflection-access-to-parameter-names-of-method-and-constructor-with-maven-gradle-and-eclipse-using-parameters-compiler-argument";

	private static final ConcurrentMap> methodParamClassMap = new ConcurrentHashMap<>();

	/**
	 * 方法参数封装,用于序列化传输参数数据,其实现类会自动根据方法名称生成get/set方法,
* 必须开启"Store information about method parameters (usable via reflection)"
* 参考:https://www.concretepage.com/java/jdk-8/java-8-reflection-access-to-parameter-names-of-method-and-constructor-with-maven-gradle-and-eclipse-using-parameters-compiler-argument
*
* 方法public CompletableFuture<User> getUser(long id) * 将会生成下面的MethodParamClass: * *
	 * public class UserService_getUser_1_6f7c1a8cf867a945306fb82a78c0a191265b9786 implements MethodParam {
	 * 	private long id;
	 * 
	 * 	public long $param0() {
	 * 		return this.id;
	 * 	}
	 * 
	 * 	public long getId() {
	 * 		return this.id;
	 * 	}
	 * 
	 * 	public void setId(long id) {
	 * 		this.id = id;
	 * 	}
	 * 
	 * 	public UserService_getUser_1_6f7c1a8cf867a945306fb82a78c0a191265b9786() {
	 * 	}
	 * 
	 * 	public UserService_getUser_1_6f7c1a8cf867a945306fb82a78c0a191265b9786(long id) {
	 * 		this.id = id;
	 * 	}
	 * }
	 * 
* * * @author Hank * */ public static Class createClass(Method method) throws CannotCompileException, NotFoundException { Objects.requireNonNull(method, "method must not be null"); if (method.getParameterCount() == 0) { return EmptyMethodParam.class; } Class methodParamClass = methodParamClassMap.get(method); if (methodParamClass != null) { return methodParamClass; } synchronized (MethodParamClassFactory.class) { methodParamClass = methodParamClassMap.get(method); if (methodParamClass != null) { return methodParamClass; } methodParamClass = doCreateClass(method); methodParamClassMap.put(method, methodParamClass); } return methodParamClass; } @SuppressWarnings("unchecked") private static Class doCreateClass(Method method) throws CannotCompileException, NotFoundException { Class[] parameterTypes = method.getParameterTypes(); Parameter[] parameters = method.getParameters(); if (!parameters[0].isNamePresent()) { throw new RuntimeException(NOT_SUPPORT_PARAMETER_NAME_MSG); } String paramTypes = Stream.of(parameterTypes)// .map(clazz -> clazz.getName())// .collect(Collectors.joining(",", "(", ")")); String hash = Hashing.murmur3_128().hashString(paramTypes, StandardCharsets.UTF_8).toString(); final String methodParamClassName = method.getDeclaringClass().getName()// + "$MethodParam"// + "$" + method.getName()// + "$" + parameterTypes.length// + "$" + hash;// 防止同名方法冲突 try { Class clazz = MethodParamClassFactory.class.getClassLoader().loadClass(methodParamClassName); if (clazz != null) { return (Class) clazz; } } catch (ClassNotFoundException e) { } // 创建类 ClassPool pool = ClassPool.getDefault(); CtClass methodParamCtClass = pool.makeClass(methodParamClassName); CtClass[] interfaces = { pool.getCtClass(MethodParam.class.getName()) }; methodParamCtClass.setInterfaces(interfaces); for (int i = 0; i < parameterTypes.length; i++) { Parameter parameter = parameters[i]; String paramName = parameter.getName(); Class paramType = parameterTypes[i]; String capitalize = Character.toUpperCase(paramName.charAt(0)) + paramName.substring(1); String getter = "get" + capitalize; String setter = "set" + capitalize; CtField ctField = new CtField(pool.get(paramType.getName()), paramName, methodParamCtClass); ctField.setModifiers(Modifier.PRIVATE); methodParamCtClass.addField(ctField); methodParamCtClass.addMethod(CtNewMethod.getter("$param" + i, ctField)); methodParamCtClass.addMethod(CtNewMethod.getter(getter, ctField)); methodParamCtClass.addMethod(CtNewMethod.setter(setter, ctField)); } // 添加无参的构造函数 CtConstructor constructor0 = new CtConstructor(null, methodParamCtClass); constructor0.setModifiers(Modifier.PUBLIC); constructor0.setBody("{}"); methodParamCtClass.addConstructor(constructor0); // 添加有参的构造函数 CtClass[] paramCtClassArray = new CtClass[method.getParameterCount()]; for (int i = 0; i < method.getParameterCount(); i++) { Class paramType = parameterTypes[i]; CtClass paramCtClass = pool.get(paramType.getName()); paramCtClassArray[i] = paramCtClass; } StringBuilder bodyBuilder = ThreadLocalStringBuilder.current(); bodyBuilder.append("{\r\n"); for (int i = 0; i < method.getParameterCount(); i++) { String paramName = parameters[i].getName(); bodyBuilder.append("$0."); bodyBuilder.append(paramName); bodyBuilder.append(" = $"); bodyBuilder.append(i + 1); bodyBuilder.append(";\r\n"); } bodyBuilder.append("}"); CtConstructor constructor1 = new CtConstructor(paramCtClassArray, methodParamCtClass); constructor1.setBody(bodyBuilder.toString()); methodParamCtClass.addConstructor(constructor1); return (Class) methodParamCtClass.toClass(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy