<commit_before>package org.grails.orm.hibernate.proxy

import groovy.transform.CompileStatic
import javassist.*
import javassist.util.proxy.MethodHandler
import javassist.util.proxy.Proxy
import org.grails.datastore.mapping.core.exceptions.ConfigurationException
import org.hibernate.internal.util.ReflectHelper
import org.hibernate.proxy.HibernateProxy
import org.hibernate.proxy.ProxyFactory
import org.hibernate.proxy.pojo.BasicLazyInitializer
import org.hibernate.proxy.pojo.javassist.SerializableProxy

import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Modifier

/**
 * In order to support all versions of Hibernate 5.x we have to create proxy factories dynamically
 *
 * This class is full of horrible hacks that we can remove when support for Hibernate versions below 5.2 is dropped.
 *
 * @author <NAME>
 * @since 6.1
 */
@CompileStatic
class ProxyFactorySupport {

    private static final Class<ProxyFactory> FACTORY
    static {
        try {
            ClassPool pool = ClassPool.default
            CtClass classArrayType = pool.getCtClass("java.lang.Class[]")

            // first make the lazy initializer
            String initializerName = "${ProxyFactorySupport.package.name}.GroovyAwareJavassistLazyInitializer"
            CtClass initializerSuperClass = getClassFromPool(pool, BasicLazyInitializer.name)
            CtClass initializerClass = pool.makeClass(initializerName, initializerSuperClass)
            initializerClass.addInterface(getClassFromPool(pool, MethodHandler.name))

            // Add Field: boolean constructed;
            def constructedField = new CtField(getClassFromPool(pool, "boolean"), "constructed", initializerClass)
            constructedField.setModifiers(Modifier.PUBLIC)
            initializerClass.addField(constructedField)

            // Add Field: boolean constructed;
            def groovyObjectMethodHandler = new CtField(getClassFromPool(pool, HibernateGroovyObjectMethodHandler.name), "groovyObjectMethodHandler", initializerClass)
            groovyObjectMethodHandler.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(groovyObjectMethodHandler)

            // Add field: HibernateProxy proxy
            CtClass proxyType = getClassFromPool(pool, HibernateProxy.name)
            def proxyField = new CtField(proxyType, "proxy", initializerClass)
            proxyField.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(proxyField)

            // Add field: Class[] interfaces
            def interfacesField = new CtField(classArrayType, "interfaces", initializerClass)
            interfacesField.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(interfacesField)

            // Add constructor
            CtClass[] existingParameterTypes = initializerSuperClass.constructors[0].parameterTypes
            CtClass[] newParameterTypes = (CtClass[])Arrays.copyOf(existingParameterTypes, existingParameterTypes.length + 2)

            newParameterTypes[existingParameterTypes.length] = classArrayType
            newParameterTypes[existingParameterTypes.length + 1] = proxyType

            def constructor = new CtConstructor(newParameterTypes, initializerClass)
            constructor.setBody("""{
        super(\$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8);
        this.interfaces = \$9;
        this.proxy = \$10;
        ( (${Proxy.name}) proxy ).setHandler( this );
        this.groovyObjectMethodHandler = new ${HibernateGroovyObjectMethodHandler.name}(this.persistentClass, this.proxy, this);
        this.constructed = true;
        }""")
            initializerClass.addConstructor(constructor)

            CtClass objectType = getClassFromPool(pool, Object.name)
            // Add method: Object serializableProxy()
            CtMethod serializableProxyMethod = new CtMethod(objectType, "serializableProxy", [] as CtClass[], initializerClass)
            serializableProxyMethod.setModifiers(Modifier.PROTECTED)
            serializableProxyMethod.setBody("""{
        return new ${SerializableProxy.name}(
                getEntityName(),
                persistentClass,
                interfaces,
                getIdentifier(),
                Boolean.FALSE,
                getIdentifierMethod,
                setIdentifierMethod,
                componentIdType);       
}""")

            // Add method: Object invoke(Object, Method, Method, Object[])
            CtClass methodType = getClassFromPool(pool, Method.name)
            CtClass objectArrayType = getClassFromPool(pool, "java.lang.Object[]")
            CtMethod invokeMethod = new CtMethod(objectType, "invoke", [objectType, methodType, methodType, objectArrayType] as CtClass[] , initializerClass)
            invokeMethod.setBody("""{
        // while constructor is running
        if (\$2.getName().equals("getHibernateLazyInitializer")) {
            return this;
        }

        Object result = groovyObjectMethodHandler.handleInvocation(\$1, \$2, \$4);
        if (groovyObjectMethodHandler.wasHandled(result)) {
           return result;
        }

        if (constructed) {
            try {
                result = invoke(\$2, \$4, \$1);
            }
            catch (Throwable t) {
                throw new Exception(t.getCause());
            }
            if (result == INVOKE_IMPLEMENTATION) {
                Object target = getImplementation();
                final Object returnValue;
                try {<commit_msg>Fix #104; Add the serializableProxyMethod to the proxy initializer class<commit_after>package org.grails.orm.hibernate.proxy

import groovy.transform.CompileStatic
import javassist.*
import javassist.util.proxy.MethodHandler
import javassist.util.proxy.Proxy
import org.grails.datastore.mapping.core.exceptions.ConfigurationException
import org.hibernate.internal.util.ReflectHelper
import org.hibernate.proxy.HibernateProxy
import org.hibernate.proxy.ProxyFactory
import org.hibernate.proxy.pojo.BasicLazyInitializer
import org.hibernate.proxy.pojo.javassist.SerializableProxy

import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Modifier

/**
 * In order to support all versions of Hibernate 5.x we have to create proxy factories dynamically
 *
 * This class is full of horrible hacks that we can remove when support for Hibernate versions below 5.2 is dropped.
 *
 * @author <NAME>
 * @since 6.1
 */
@CompileStatic
class ProxyFactorySupport {

    private static final Class<ProxyFactory> FACTORY
    static {
        try {
            ClassPool pool = ClassPool.default
            CtClass classArrayType = pool.getCtClass("java.lang.Class[]")

            // first make the lazy initializer
            String initializerName = "${ProxyFactorySupport.package.name}.GroovyAwareJavassistLazyInitializer"
            CtClass initializerSuperClass = getClassFromPool(pool, BasicLazyInitializer.name)
            CtClass initializerClass = pool.makeClass(initializerName, initializerSuperClass)
            initializerClass.addInterface(getClassFromPool(pool, MethodHandler.name))

            // Add Field: boolean constructed;
            def constructedField = new CtField(getClassFromPool(pool, "boolean"), "constructed", initializerClass)
            constructedField.setModifiers(Modifier.PUBLIC)
            initializerClass.addField(constructedField)

            // Add Field: boolean constructed;
            def groovyObjectMethodHandler = new CtField(getClassFromPool(pool, HibernateGroovyObjectMethodHandler.name), "groovyObjectMethodHandler", initializerClass)
            groovyObjectMethodHandler.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(groovyObjectMethodHandler)

            // Add field: HibernateProxy proxy
            CtClass proxyType = getClassFromPool(pool, HibernateProxy.name)
            def proxyField = new CtField(proxyType, "proxy", initializerClass)
            proxyField.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(proxyField)

            // Add field: Class[] interfaces
            def interfacesField = new CtField(classArrayType, "interfaces", initializerClass)
            interfacesField.setModifiers(Modifier.PRIVATE | Modifier.FINAL)
            initializerClass.addField(interfacesField)

            // Add constructor
            CtClass[] existingParameterTypes = initializerSuperClass.constructors[0].parameterTypes
            CtClass[] newParameterTypes = (CtClass[])Arrays.copyOf(existingParameterTypes, existingParameterTypes.length + 2)

            newParameterTypes[existingParameterTypes.length] = classArrayType
            newParameterTypes[existingParameterTypes.length + 1] = proxyType

            def constructor = new CtConstructor(newParameterTypes, initializerClass)
            constructor.setBody("""{
        super(\$1, \$2, \$3, \$4, \$5, \$6, \$7, \$8);
        this.interfaces = \$9;
        this.proxy = \$10;
        ( (${Proxy.name}) proxy ).setHandler( this );
        this.groovyObjectMethodHandler = new ${HibernateGroovyObjectMethodHandler.name}(this.persistentClass, this.proxy, this);
        this.constructed = true;
        }""")
            initializerClass.addConstructor(constructor)

            CtClass objectType = getClassFromPool(pool, Object.name)
            // Add method: Object serializableProxy()
            CtMethod serializableProxyMethod = new CtMethod(objectType, "serializableProxy", [] as CtClass[], initializerClass)
            serializableProxyMethod.setModifiers(Modifier.PROTECTED)
            serializableProxyMethod.setBody("""{
        return new ${SerializableProxy.name}(
                getEntityName(),
                persistentClass,
                interfaces,
                getIdentifier(),
                Boolean.FALSE,
                getIdentifierMethod,
                setIdentifierMethod,
                componentIdType);       
}""")
            initializerClass.addMethod(serializableProxyMethod)

            // Add method: Object invoke(Object, Method, Method, Object[])
            CtClass methodType = getClassFromPool(pool, Method.name)
            CtClass objectArrayType = getClassFromPool(pool, "java.lang.Object[]")
            CtMethod invokeMethod = new CtMethod(objectType, "invoke", [objectType, methodType, methodType, objectArrayType] as CtClass[] , initializerClass)
            invokeMethod.setBody("""{
        // while constructor is running
        if (\$2.getName().equals("getHibernateLazyInitializer")) {
            return this;
        }

        Object result = groovyObjectMethodHandler.handleInvocation(\$1, \$2, \$4);
        if (groovyObjectMethodHandler.wasHandled(result)) {
           return result;
        }

        if (constructed) {
            try {
                result = invoke(\$2, \$4, \$1);
            }
            catch (Throwable t) {
                throw new Exception(t.getCause());
            }
            if (result == INVOKE_IMPLEMENTATION) {
                Object target = getImplementation();
                final Object returnValue;
                try {
{'fraction_non_alphanumeric': 0.08905265027079819, 'fraction_numerical': 0.00488324602681346, 'mean_word_length': 2.777330650570087, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6749419', 'n_tokens_mistral': 3010, 'n_tokens_neox': 2813, 'n_words': 612}