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

org.hibernate.envers.internal.tools.MapProxyTool Maven / Gradle / Ivy

There is a newer version: 7.0.0.Beta1
Show newest version
package org.hibernate.envers.internal.tools;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.NotFoundException;

import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.envers.internal.entities.PropertyData;

import static org.hibernate.envers.internal.tools.StringTools.capitalizeFirst;
import static org.hibernate.envers.internal.tools.StringTools.getLastComponent;

/**
 * @author Lukasz Zuchowski (author at zuchos dot com)
 */
public final class MapProxyTool {
	private MapProxyTool() {
	}

	/**
     * @param className               Name of the class to construct (should be unique within class loader)
     * @param map                instance that will be proxied by java bean
     * @param propertyDatas      properties that should java bean declare
     * @param classLoaderService
     * @return new instance of proxy
     * @author Lukasz Zuchowski (author at zuchos dot com)
     * Creates instance of map proxy class. This proxy class will be a java bean with properties from propertyDatas.
     * Instance will proxy calls to instance of the map passed as parameter.
     */
    public static Object newInstanceOfBeanProxyForMap(String className, Map map, Set propertyDatas, ClassLoaderService classLoaderService) {
        Map> properties = prepareProperties(propertyDatas);
        return createNewInstance(map, classForName(className, properties, classLoaderService));
    }

    private static Object createNewInstance(Map map, Class aClass) {
        try {
            return aClass.getConstructor(Map.class).newInstance(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static Map> prepareProperties(Set propertyDatas) {
        Map> properties = new HashMap>();
        for (PropertyData propertyData : propertyDatas) {
            properties.put(propertyData.getBeanName(), Object.class);
        }
        return properties;
    }

    private static Class loadClass(String className, ClassLoaderService classLoaderService) {
        try {
            return ReflectionTools.loadClass(className, classLoaderService);
        } catch (ClassLoadingException e) {
            return null;
        }

    }

    /**
     * Generates/loads proxy class for given name with properties for map.
     * @param className name of the class that will be generated/loaded
     * @param properties list of properties that should be exposed via java bean
     * @param classLoaderService
     * @return proxy class that wraps map into java bean
     */
    public static Class classForName(String className, Map> properties, ClassLoaderService classLoaderService) {
        Class aClass = loadClass(className, classLoaderService);
        if (aClass == null) {
            aClass = generate(className, properties);
        }
        return aClass;
    }

    /**
     * Protected for test only
     */
    protected static Class generate(String className, Map> properties) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.makeClass(className);

            cc.addInterface(resolveCtClass(Serializable.class));
            cc.addField(new CtField(resolveCtClass(Map.class), "theMap", cc));
            cc.addConstructor(generateConstructor(className, cc));

            for (Entry> entry : properties.entrySet()) {

                // add getter
                cc.addMethod(generateGetter(cc, entry.getKey(), entry.getValue()));

                // add setter
                cc.addMethod(generateSetter(cc, entry.getKey(), entry.getValue()));
            }
            return cc.toClass();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static CtConstructor generateConstructor(String className, CtClass cc) throws NotFoundException, CannotCompileException {
        StringBuffer sb = new StringBuffer();
        sb.append("public ").append(getLastComponent(className)).append("(").append(Map.class.getName()).append(" map)").append("{")
                .append("this.theMap = map;").append("}");
        System.out.println(sb);
        return CtNewConstructor.make(sb.toString(), cc);
    }

    private static CtMethod generateGetter(CtClass declaringClass, String fieldName, Class fieldClass)
            throws CannotCompileException {

        String getterName = "get" + capitalizeFirst(fieldName);

        StringBuilder sb = new StringBuilder();
        sb.append("public ").append(fieldClass.getName()).append(" ")
                .append(getterName).append("(){").append("return (").append(fieldClass.getName()).append(")this.theMap.get(\"")
                .append(fieldName).append("\")").append(";").append("}");
        return CtMethod.make(sb.toString(), declaringClass);
    }

    private static CtMethod generateSetter(CtClass declaringClass, String fieldName, Class fieldClass)
            throws CannotCompileException {

        String setterName = "set" + capitalizeFirst(fieldName);

        StringBuilder sb = new StringBuilder();
        sb.append("public void ").append(setterName).append("(")
                .append(fieldClass.getName()).append(" ").append(fieldName)
                .append(")").append("{").append("this.theMap.put(\"").append(fieldName)
                .append("\",").append(fieldName).append(")").append(";").append("}");
        return CtMethod.make(sb.toString(), declaringClass);
    }

    private static CtClass resolveCtClass(Class clazz) throws NotFoundException {
        return resolveCtClass(clazz.getName());
    }


    private static CtClass resolveCtClass(String clazz) throws NotFoundException {
        try {
            ClassPool pool = ClassPool.getDefault();
            return pool.get(clazz);
        } catch (NotFoundException e) {
            return null;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy