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

com.firefly.utils.classproxy.ArrayProxyFactoryUsingJavassist Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.firefly.utils.classproxy;

import java.util.Map;
import java.util.UUID;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import com.firefly.utils.ReflectUtils.ArrayProxy;
import com.firefly.utils.collection.ConcurrentReferenceHashMap;
import com.firefly.utils.StringUtils;

public class ArrayProxyFactoryUsingJavassist extends AbstractArrayProxyFactory {

	private static final Map, ArrayProxy> arrayCache = new ConcurrentReferenceHashMap<>(256);
	public static final ArrayProxyFactoryUsingJavassist INSTANCE = new ArrayProxyFactoryUsingJavassist();
	
	private ArrayProxyFactoryUsingJavassist() {}
	
	@Override
	public ArrayProxy getArrayProxy(Class clazz) throws Throwable {
		if(!clazz.isArray())
			throw new IllegalArgumentException("type error, it's not array");
			
		ArrayProxy ret = arrayCache.get(clazz);
		if(ret != null)
			return ret;
		
		synchronized(arrayCache) {
			ret = arrayCache.get(clazz);
			if(ret != null)
				return ret;
			
			ret = _getArrayProxy(clazz);
			arrayCache.put(clazz, ret);
			return ret;
		}
	}
	
	@SuppressWarnings("unchecked")
	private ArrayProxy _getArrayProxy(Class clazz) throws Throwable {
//		long start = System.currentTimeMillis();
		ClassPool classPool = ClassPool.getDefault();
		classPool.insertClassPath(new ClassClassPath(ArrayProxy.class));
		
		CtClass cc = classPool.makeClass("com.firefly.utils.ArrayField" + UUID.randomUUID().toString().replace("-", ""));
		cc.addInterface(classPool.get(ArrayProxy.class.getName()));
		
		cc.addMethod(CtMethod.make(createArraySizeCode(clazz), cc));
		cc.addMethod(CtMethod.make(createArrayGetCode(clazz), cc));
		cc.addMethod(CtMethod.make(createArraySetCode(clazz), cc));
		
		ArrayProxy ret = (ArrayProxy) cc.toClass(classLoader, null).getConstructor().newInstance();
//		long end = System.currentTimeMillis();
//		System.out.println("Javassist generates class proxy time -> " + (end - start));
		return ret;
	}
	
	private String createArraySetCode(Class clazz) {
		StringBuilder code = new StringBuilder();
		code.append("public void set(Object array, int index, Object value){\n")
			.append(StringUtils.replace("\t(({})array)[index] = ", clazz.getCanonicalName()));
		
		Class componentType = clazz.getComponentType();
		if(componentType.isPrimitive()) {
			code.append(StringUtils.replace("(({})value).{}Value()", primitiveWrapMap.get(componentType), componentType.getCanonicalName()));
		} else {
			code.append(StringUtils.replace("({})value", componentType.getCanonicalName()));
		}
		
		code.append(";\n")
			.append("}");
		return code.toString();
	}
	
	private String createArrayGetCode(Class clazz) {
		StringBuilder code = new StringBuilder();
		code.append("public Object get(Object array, int index){\n")
			.append("\treturn ");
		Class componentType = clazz.getComponentType();
		boolean hasValueOf = false;
		if(componentType.isPrimitive()) {
			code.append(StringUtils.replace("(Object){}.valueOf(", primitiveWrapMap.get(componentType)));
			hasValueOf = true;
		}
		
		code.append(StringUtils.replace("(({})array)[index]", clazz.getCanonicalName()));
		if(hasValueOf)
			code.append(")");
		
		code.append(";\n")
		.append("}");
		return code.toString();
	}
	
	private String createArraySizeCode(Class clazz) {
		StringBuilder code = new StringBuilder();
		code.append("public int size(Object array){\n")
			.append("\treturn ").append(StringUtils.replace("(({})array).length;\n", clazz.getCanonicalName()))
			.append("}");
		return code.toString();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy