Issue #23628 + #23507 JDK17 support - replaced deprecated Proxy.getProxyClass

- EJB tests failed on JDK17 because of this
- also more consistent generateAndLoad (to be finished in next commits)
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java
index 9a46d90..fdfae99 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/EJBUtils.java
@@ -387,20 +387,14 @@
             return generatedRemoteIntfName;
         }
 
-        Wrapper._setClassLoader(appClassLoader);
-        try {
-            if (generatedRemoteIntf == null) {
-                RemoteGenerator generator = new RemoteGenerator(appClassLoader, businessInterfaceName);
-                generateAndLoad(generator, appClassLoader);
-            }
-            if (generatedRemoteWrapper == null) {
-                Remote30WrapperGenerator generator
-                    = new Remote30WrapperGenerator(appClassLoader, businessInterfaceName, generatedRemoteIntfName);
-                generateAndLoad(generator, appClassLoader);
-            }
-        } finally {
-            // Make sure no classloader is bound to threadlocal: avoid possible classloader leak.
-            Wrapper._setClassLoader(null) ;
+        if (generatedRemoteIntf == null) {
+            RemoteGenerator generator = new RemoteGenerator(appClassLoader, businessInterfaceName);
+            generateAndLoad(generator);
+        }
+        if (generatedRemoteWrapper == null) {
+            Remote30WrapperGenerator generator
+                = new Remote30WrapperGenerator(appClassLoader, businessInterfaceName, generatedRemoteIntfName);
+            generateAndLoad(generator);
         }
         return generatedRemoteIntfName;
     }
@@ -411,17 +405,17 @@
         if (generatedGenericEJBHomeClass != null) {
             return generatedGenericEJBHomeClass;
         }
-        final GenericHomeGenerator generator = new GenericHomeGenerator();
-        return generateAndLoad(generator, appClassLoader);
+        final GenericHomeGenerator generator = new GenericHomeGenerator(appClassLoader);
+        return generateAndLoad(generator);
     }
 
 
-    public static Class<?> generateSEI(ClassGeneratorFactory cgf, ClassLoader loader) {
-        Class<?> clazz = loadClassIgnoringExceptions(loader, cgf.getGeneratedClassName());
+    public static Class<?> generateSEI(ClassGeneratorFactory cgf) {
+        Class<?> clazz = loadClassIgnoringExceptions(cgf.getClassLoader(), cgf.getGeneratedClassName());
         if (clazz != null) {
             return clazz;
         }
-        return generateAndLoad(cgf, loader);
+        return generateAndLoad(cgf);
     }
 
 
@@ -431,35 +425,40 @@
      * and if it wasn't found, generator knows it's definition.
      */
     // made package visible just for tests
-    static synchronized Class<?> generateAndLoad(final ClassGeneratorFactory generator, final ClassLoader loader) {
-        Class<?> clazz = loadClassIgnoringExceptions(loader, generator.getGeneratedClassName());
+    static synchronized Class<?> generateAndLoad(final ClassGeneratorFactory generator) {
+        Class<?> clazz = loadClassIgnoringExceptions(generator.getClassLoader(), generator.getGeneratedClassName());
         if (clazz != null) {
             return clazz;
         }
 
-        generator.evaluate();
-
-        final Properties props = new Properties();
-        if (_logger.isLoggable(Level.FINEST)) {
-            props.put(DUMP_AFTER_SETUP_VISITOR, "true");
-            props.put(TRACE_BYTE_CODE_GENERATION, "true");
-            props.put(USE_ASM_VERIFIER, "true");
-            try {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                PrintStream ps = new PrintStream(baos);
-                Wrapper._sourceCode(ps, props);
-                _logger.fine(baos.toString());
-            } catch (Exception e) {
-                _logger.log(Level.SEVERE, "Exception generating src for logs", e);
+        try {
+            generator.evaluate();
+            final Properties props = new Properties();
+            if (_logger.isLoggable(Level.FINEST)) {
+                props.put(DUMP_AFTER_SETUP_VISITOR, "true");
+                props.put(TRACE_BYTE_CODE_GENERATION, "true");
+                props.put(USE_ASM_VERIFIER, "true");
+                try {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    PrintStream ps = new PrintStream(baos);
+                    Wrapper._sourceCode(ps, props);
+                    _logger.fine(baos.toString());
+                } catch (Exception e) {
+                    _logger.log(Level.SEVERE, "Exception generating src for logs", e);
+                }
             }
-        }
 
-        if (System.getSecurityManager() == null) {
-            return Wrapper._generate(loader, generator.getAnchorClass().getProtectionDomain(), props);
+            // FIXME: Wrapper._generate(anchorClass, props) generates class in anchor class's classloader,
+            //        not the provided. That is why we still use the deprecated method.
+            if (System.getSecurityManager() == null) {
+                return Wrapper._generate(generator.getClassLoader(), generator.getAnchorClass().getProtectionDomain(), props);
+            }
+            PrivilegedAction<Class<?>> action = () -> Wrapper._generate(generator.getClassLoader(), generator.getAnchorClass().getProtectionDomain(), props);
+            return AccessController.doPrivileged(action);
+        } finally {
+            Wrapper._clear();
+            Wrapper._setClassLoader(null);
         }
-        PrivilegedAction<Class<?>> action = () ->
-            Wrapper._generate(loader, generator.getAnchorClass().getProtectionDomain(), props);
-        return AccessController.doPrivileged(action);
     }
 
     private static Class<?> loadClassIgnoringExceptions(ClassLoader classLoader, String className) {
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java
index 84a1263..ced04ac 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ClassGeneratorFactory.java
@@ -36,7 +36,15 @@
     Class<?> getAnchorClass();
 
     /**
+     * @return {@link ClassLoader} owning the generated class.
+     */
+    ClassLoader getClassLoader();
+
+    /**
      * Calls {@link Wrapper} methods to configure the class definition.
+     * The {@link Wrapper} uses {@link ThreadLocal} internally, so you should
+     * always call {@link Wrapper#_clear()} in finally block after generation
+     * to avoid leakages.
      */
     void evaluate();
 }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
index 63c52a8..5191562 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Generator.java
@@ -27,6 +27,26 @@
  */
 public abstract class Generator implements ClassGeneratorFactory {
 
+    protected final ClassLoader loader;
+
+
+    /**
+     * @param loader {@link ClassLoader} owning generated classes
+     */
+    public Generator(final ClassLoader loader) {
+        this.loader = loader;
+    }
+
+
+    /**
+     * @return {@link ClassLoader} owning the generated class.
+     */
+    @Override
+    public ClassLoader getClassLoader() {
+        return this.loader;
+    }
+
+
     /**
      * @return the package name or null.
      */
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java
index 789dc91..3b4207f 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/GenericHomeGenerator.java
@@ -32,6 +32,7 @@
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package;
+import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._setClassLoader;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t;
 
 /**
@@ -48,6 +49,14 @@
         + ".GenericEJBHome_Generated";
 
     /**
+     * @param loader {@link ClassLoader} owning generated classes
+     */
+    public GenericHomeGenerator(ClassLoader loader) {
+        super(loader);
+    }
+
+
+    /**
      * Get the fully qualified name of the generated class.
      * @return the name of the generated class.
      */
@@ -67,6 +76,8 @@
     public void evaluate() {
         _clear();
 
+        _setClassLoader(loader);
+
         String packageName = getPackageName(getGeneratedClassName());
         String simpleName = getBaseName(getGeneratedClassName());
 
@@ -80,7 +91,7 @@
 
         _end();
 
-        _classGenerator() ;
+        _classGenerator();
     }
 
 }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java
index c90f20a..96ff14f 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/Remote30WrapperGenerator.java
@@ -61,9 +61,6 @@
     private final String remoteClientSimpleName;
     private final Method[] methodsToGenerate;
 
-    private final ClassLoader loader;
-
-
     /**
      * Adds _Wrapper to the original name.
      *
@@ -89,7 +86,7 @@
     public Remote30WrapperGenerator(ClassLoader loader, String businessIntfName, String remoteInterfaceName)
         throws GeneratorException {
 
-        this.loader = loader;
+        super(loader);
         this.remoteInterfaceName = remoteInterfaceName;
 
         try {
@@ -130,6 +127,8 @@
 
         _clear();
 
+        _setClassLoader(loader);
+
         if (remoteClientPackageName != null) {
             _package(remoteClientPackageName);
         } else {
@@ -168,7 +167,7 @@
             LOG.log(Level.WARNING, "Got exception when generating byte code", e);
         }
 
-        _classGenerator() ;
+        _classGenerator();
     }
 
 
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java
index 8580703..9c39dd0 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/RemoteGenerator.java
@@ -36,6 +36,7 @@
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package;
+import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._setClassLoader;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t;
 
 /**
@@ -75,6 +76,7 @@
      * @throws InvalidBean if the businessInterface doesn't exist.
      */
     public RemoteGenerator(ClassLoader classLoader, String businessIntf) throws InvalidBean {
+        super(classLoader);
         try {
             businessInterface = classLoader.loadClass(businessIntf);
         } catch (ClassNotFoundException ex) {
@@ -115,6 +117,8 @@
 
         _clear();
 
+        _setClassLoader(loader);
+
         if (remoteInterfacePackageName != null) {
             _package(remoteInterfacePackageName);
         } else {
@@ -132,7 +136,7 @@
 
         _end();
 
-        _classGenerator() ;
+        _classGenerator();
     }
 
 
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java
index ed9abd8..7e601a6 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/ServiceInterfaceGenerator.java
@@ -35,6 +35,7 @@
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._interface;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._method;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._package;
+import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._setClassLoader;
 import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper._t;
 
 /**
@@ -51,11 +52,15 @@
     private final String serviceIntfSimpleName;
     private final Method[] intfMethods;
 
-   /**
+    /**
      * Construct the Wrapper generator with the specified deployment
      * descriptor and class loader.
+     *
+     * @param loader {@link ClassLoader} owning generated classes
+     * @param ejbClass
      */
-    public ServiceInterfaceGenerator(Class<?> ejbClass) {
+    public ServiceInterfaceGenerator(final ClassLoader loader, final Class<?> ejbClass) {
+        super(loader);
         this.ejbClass = ejbClass;
         packageName = getPackageName(ejbClass.getName());
         serviceIntfSimpleName = getServiceIntfName(ejbClass);
@@ -91,6 +96,8 @@
     public void evaluate() {
         _clear();
 
+        _setClassLoader(loader);
+
         if (packageName != null) {
             _package(packageName);
         }
diff --git a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java
index f19c2fa..4558ece 100644
--- a/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java
+++ b/appserver/ejb/ejb-container/src/main/java/com/sun/ejb/containers/BaseContainer.java
@@ -17,13 +17,12 @@
 package com.sun.ejb.containers;
 
 import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
 import java.rmi.AccessException;
+import java.rmi.Remote;
 import java.rmi.RemoteException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -279,9 +278,6 @@
     // object as ejbLocalHome, for example in the case of dynamic proxies.
     protected EJBLocalHomeImpl ejbLocalHomeImpl;
 
-    // Constructor used to instantiate ejb local object proxy.
-    private Constructor ejbLocalObjectProxyCtor;
-
     //
     // Data members for 3.x Local business view
     //
@@ -307,12 +303,6 @@
     // Implementation of internal local business home interface.
     protected EJBLocalHomeImpl ejbOptionalLocalBusinessHomeImpl;
 
-    // Constructor used to instantiate local business object proxy.
-    private Constructor ejbLocalBusinessObjectProxyCtor;
-
-    // Constructor used to instantiate local business object proxy.
-    private Constructor ejbOptionalLocalBusinessObjectProxyCtor;
-
     private Collection<EjbContainerInterceptor> interceptors = null;
 
     /*****************************************
@@ -353,9 +343,6 @@
     // Remote interface proxy class
     private Class ejbObjectProxyClass;
 
-    // Remote interface proxy constructor.
-    private Constructor ejbObjectProxyCtor;
-
     // RemoteReference Factory for RemoteHome view
     protected RemoteReferenceFactory remoteHomeRefFactory = null;
 
@@ -511,6 +498,10 @@
 
     private final JCDIService jcdiService;
 
+    private Class[] ejbLocalBusinessProxyInterfaces;
+
+    private Class[] ejbOptionalLocalBusinessHomeProxyInterfaces;
+
     /**
      * This constructor is called from ContainerFactoryImpl when an EJB Jar is deployed.
      */
@@ -1101,8 +1092,8 @@
             Class serviceEndpointIntfClass = loader.loadClass(webServiceEndpoint.getServiceEndpointInterface());
 
             if (!serviceEndpointIntfClass.isInterface()) {
-                ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(ejbClass);
-                serviceEndpointIntfClass = EJBUtils.generateSEI(generator, loader);
+                ServiceInterfaceGenerator generator = new ServiceInterfaceGenerator(loader, ejbClass);
+                serviceEndpointIntfClass = EJBUtils.generateSEI(generator);
                 if (serviceEndpointIntfClass == null) {
                     throw new RuntimeException(localStrings.getLocalString("ejb.error_generating_sei",
                         "Error in generating service endpoint interface class for EJB class {0}", this.ejbClass));
@@ -1170,12 +1161,6 @@
                 this.ejbHomeImpl = instantiateEJBHomeImpl();
                 this.ejbHome = ejbHomeImpl.getEJBHome();
 
-                // Since some containers might create multiple EJBObjects for
-                // the same ejb, make sure we use the same Proxy class to
-                // instantiate all the proxy instances.
-                ejbObjectProxyClass = Proxy.getProxyClass(loader, new Class[] { remoteIntf });
-                ejbObjectProxyCtor = ejbObjectProxyClass.getConstructor(new Class[] { InvocationHandler.class });
-
                 //
                 // Make sure all Home/Remote interfaces conform to RMI-IIOP
                 // rules.  Checking for conformance here keeps the exposed
@@ -1230,11 +1215,6 @@
                 getProtocolManager().validateTargetObjectInterfaces(this.ejbRemoteBusinessHome);
 
                 for (RemoteBusinessIntfInfo next : remoteBusinessIntfInfo.values()) {
-
-                    next.proxyClass = Proxy.getProxyClass(loader, new Class[] { next.generatedRemoteIntf });
-
-                    next.proxyCtor = next.proxyClass.getConstructor(new Class[] { InvocationHandler.class });
-
                     // Remotereference factory needs instances of
                     // Home and Remote to get repository Ids since it
                     // doesn't have stubs and ties.  This must be done before
@@ -1350,12 +1330,6 @@
                 this.ejbLocalHomeImpl = instantiateEJBLocalHomeImpl();
                 this.ejbLocalHome = ejbLocalHomeImpl.getEJBLocalHome();
 
-                // Since some containers might create multiple EJBLocalObjects
-                // for the same ejb, make sure we use the same Proxy class to
-                // instantiate all the proxy instances.
-                Class ejbLocalObjectProxyClass = Proxy.getProxyClass(loader, new Class[] { IndirectlySerializable.class, localIntf });
-                ejbLocalObjectProxyCtor = ejbLocalObjectProxyClass.getConstructor(new Class[] { InvocationHandler.class });
-
                 // Portable JNDI name for EJB 2.x LocalHome.  We don't provide a
                 // glassfish-specific way of accessing Local EJBs.
 
@@ -1368,24 +1342,20 @@
                 ejbLocalBusinessHomeImpl = instantiateEJBLocalBusinessHomeImpl();
                 ejbLocalBusinessHome = (GenericEJBLocalHome) ejbLocalBusinessHomeImpl.getEJBLocalHome();
 
-                Class[] proxyInterfaces = new Class[localBusinessIntfs.size() + 1];
-                proxyInterfaces[0] = IndirectlySerializable.class;
+                ejbLocalBusinessProxyInterfaces = new Class[localBusinessIntfs.size() + 1];
+                ejbLocalBusinessProxyInterfaces[0] = IndirectlySerializable.class;
                 int index = 1;
                 for (Class next : localBusinessIntfs) {
-                    proxyInterfaces[index] = next;
+                    ejbLocalBusinessProxyInterfaces[index] = next;
                     index++;
                 }
 
-                Class proxyClass = Proxy.getProxyClass(loader, proxyInterfaces);
-                ejbLocalBusinessObjectProxyCtor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
-
                 for (Class next : localBusinessIntfs) {
                     // Portable JNDI name for EJB 3.x Local business interface.
                     // We don't provide a glassfish-specific way of accessing Local EJBs.
                     JavaGlobalJndiNamingObjectProxy namingProxy = new JavaGlobalJndiNamingObjectProxy(this, next.getName());
                     intfsForPortableJndi.put(next.getName(), namingProxy);
                 }
-
             }
 
             if (hasOptionalLocalBusinessView) {
@@ -1394,14 +1364,12 @@
 
                 ejbOptionalLocalBusinessHome = (GenericEJBLocalHome) ejbOptionalLocalBusinessHomeImpl.getEJBLocalHome();
 
-                Class[] proxyInterfaces = new Class[2];
-                proxyInterfaces[0] = IndirectlySerializable.class;
+                ejbOptionalLocalBusinessHomeProxyInterfaces = new Class[2];
+                ejbOptionalLocalBusinessHomeProxyInterfaces[0] = IndirectlySerializable.class;
+
                 String optionalIntfName = EJBUtils.getGeneratedOptionalInterfaceName(ejbClass.getName());
-
-                proxyInterfaces[1] = ejbGeneratedOptionalLocalBusinessIntfClass = optIntfClassLoader.loadClass(optionalIntfName);
-
-                Class proxyClass = Proxy.getProxyClass(loader, proxyInterfaces);
-                ejbOptionalLocalBusinessObjectProxyCtor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+                ejbGeneratedOptionalLocalBusinessIntfClass = optIntfClassLoader.loadClass(optionalIntfName);
+                ejbOptionalLocalBusinessHomeProxyInterfaces[1] = ejbGeneratedOptionalLocalBusinessIntfClass;
 
                 // Portable JNDI name for no-interface view.
                 // We don't provide a glassfish-specific way of accessing the
@@ -3307,9 +3275,8 @@
         handler.setMethodMap(proxyInvocationInfoMap);
 
         EJBHomeImpl remoteBusinessHomeImpl = handler;
-
-        EJBHome ejbRemoteBusinessHomeProxy = (EJBHome) Proxy.newProxyInstance(loader, new Class[] { remoteBusinessHomeIntf }, handler);
-
+        EJBHome ejbRemoteBusinessHomeProxy = (EJBHome) Proxy.newProxyInstance(
+            loader, new Class[] {remoteBusinessHomeIntf}, handler);
         handler.setProxy(ejbRemoteBusinessHomeProxy);
 
         remoteBusinessHomeImpl.setContainer(this);
@@ -3406,7 +3373,8 @@
         localObjImpl = handler;
 
         try {
-            EJBLocalObject localObjectProxy = (EJBLocalObject) ejbLocalObjectProxyCtor.newInstance(new Object[] { handler });
+            EJBLocalObject localObjectProxy = (EJBLocalObject) Proxy.newProxyInstance(
+                loader, new Class[] {IndirectlySerializable.class, localIntf}, handler);
             handler.setProxy(localObjectProxy);
         } catch (ClassCastException e) {
             String msg = localStrings.getLocalString("ejb.basecontainer_invalid_local_interface",
@@ -3428,9 +3396,7 @@
         EJBLocalObjectInvocationHandler handler = new EJBLocalObjectInvocationHandler(proxyInvocationInfoMap, false);
 
         EJBLocalObjectImpl localBusinessObjImpl = handler;
-
-        ejbLocalBusinessObjectProxyCtor.newInstance(new Object[] { handler });
-
+        Proxy.newProxyInstance(loader, ejbLocalBusinessProxyInterfaces, handler);
         localBusinessObjImpl.setContainer(this);
 
         for (Class businessIntfClass : localBusinessIntfs) {
@@ -3445,17 +3411,15 @@
     protected EJBLocalObjectImpl instantiateOptionalEJBLocalBusinessObjectImpl() throws Exception {
 
         EJBLocalObjectInvocationHandler handler = new EJBLocalObjectInvocationHandler(proxyInvocationInfoMap, true);
-
         EJBLocalObjectImpl localBusinessObjImpl = handler;
-
-        ejbOptionalLocalBusinessObjectProxyCtor.newInstance(new Object[] { handler });
-
+        Proxy.newProxyInstance(loader, ejbOptionalLocalBusinessHomeProxyInterfaces, handler);
         localBusinessObjImpl.setContainer(this);
 
         Class businessIntfClass = ejbGeneratedOptionalLocalBusinessIntfClass;
-        EJBLocalObjectInvocationHandlerDelegate delegate = new EJBLocalObjectInvocationHandlerDelegate(businessIntfClass, getContainerId(),
-            handler);
-        Proxy proxy = (Proxy) Proxy.newProxyInstance(loader, new Class[] { IndirectlySerializable.class, businessIntfClass }, delegate);
+        EJBLocalObjectInvocationHandlerDelegate delegate = new EJBLocalObjectInvocationHandlerDelegate(
+            businessIntfClass, getContainerId(), handler);
+        Proxy proxy = (Proxy) Proxy.newProxyInstance(
+            loader, new Class[] {IndirectlySerializable.class, businessIntfClass}, delegate);
 
         String beanSubClassName = ejbGeneratedOptionalLocalBusinessIntfClass.getName() + "__Bean__";
 
@@ -3465,7 +3429,7 @@
         optIntfClassLoader.loadClass(ejbGeneratedOptionalLocalBusinessIntfClass.getName());
 
         Class subClass = optIntfClassLoader.loadClass(beanSubClassName);
-        OptionalLocalInterfaceProvider provider = (OptionalLocalInterfaceProvider) subClass.newInstance();
+        OptionalLocalInterfaceProvider provider = (OptionalLocalInterfaceProvider) subClass.getConstructor().newInstance();
         provider.setOptionalLocalIntfProxy(proxy);
         localBusinessObjImpl.mapClientObject(ejbClass.getName(), provider);
 
@@ -3481,7 +3445,8 @@
         EJBObjectImpl ejbObjImpl = handler;
 
         try {
-            EJBObject ejbObjectProxy = (EJBObject) ejbObjectProxyCtor.newInstance(new Object[] { handler });
+            EJBObject ejbObjectProxy = (EJBObject) Proxy.newProxyInstance(loader, new Class[] {remoteIntf}, handler);
+            this.ejbObjectProxyClass = ejbObjectProxyClass == null ? ejbObjectProxy.getClass() : ejbObjectProxyClass;
             handler.setEJBObject(ejbObjectProxy);
         } catch (ClassCastException e) {
             String msg = localStrings.getLocalString("ejb.basecontainer_invalid_remote_interface",
@@ -3519,11 +3484,10 @@
         for (RemoteBusinessIntfInfo next : remoteBusinessIntfInfo.values()) {
 
             EJBObjectInvocationHandlerDelegate delegate = new EJBObjectInvocationHandlerDelegate(next.remoteBusinessIntf, handler);
-
-            java.rmi.Remote ejbBusinessObjectProxy = (java.rmi.Remote) next.proxyCtor.newInstance(new Object[] { delegate });
-
+            Remote ejbBusinessObjectProxy = (Remote) Proxy.newProxyInstance(
+                loader, new Class[] {next.generatedRemoteIntf}, delegate);
+            next.proxyClass = ejbBusinessObjectProxy.getClass();
             ejbBusinessObjImpl.setEJBObject(next.generatedRemoteIntf.getName(), ejbBusinessObjectProxy);
-
         }
 
         ejbBusinessObjImpl.setContainer(this);
@@ -3935,7 +3899,9 @@
                         remoteHomeRefFactory.cleanupClass(homeIntf);
                         remoteHomeRefFactory.cleanupClass(remoteIntf);
                         remoteHomeRefFactory.cleanupClass(ejbHome.getClass());
-                        remoteHomeRefFactory.cleanupClass(ejbObjectProxyClass);
+                        if (ejbObjectProxyClass != null) {
+                            remoteHomeRefFactory.cleanupClass(ejbObjectProxyClass);
+                        }
 
                         // destroy the factory itself
                         remoteHomeRefFactory.destroy();
@@ -3956,7 +3922,9 @@
 
                             next.referenceFactory.cleanupClass(next.generatedRemoteIntf);
 
-                            next.referenceFactory.cleanupClass(next.proxyClass);
+                            if (next.proxyClass != null) {
+                                next.referenceFactory.cleanupClass(next.proxyClass);
+                            }
 
                             // destroy the factory itself
                             next.referenceFactory.destroy();
@@ -4621,14 +4589,11 @@
 }
 
 final class RemoteBusinessIntfInfo {
-
     Class generatedRemoteIntf;
     Class remoteBusinessIntf;
     String jndiName;
     RemoteReferenceFactory referenceFactory;
     Class proxyClass;
-    Constructor proxyCtor;
-
 }
 
 final class SafeProperties extends Properties {
diff --git a/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java b/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java
index 7aa18e0..654dd76 100644
--- a/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java
+++ b/appserver/ejb/ejb-container/src/test/java/com/sun/ejb/EJBUtilsTest.java
@@ -106,7 +106,7 @@
         // random interface for the test
         String interfaceName = ClassGeneratorFactory.class.getName();
         Generator generator = new Remote30WrapperGenerator(loader, interfaceName, interfaceName);
-        Class<?> newClass = EJBUtils.generateAndLoad(generator, loader);
+        Class<?> newClass = EJBUtils.generateAndLoad(generator);
         assertNotNull(newClass);
         assertEquals(generator.getGeneratedClassName(), newClass.getName());
     }
@@ -138,8 +138,8 @@
     @Test
     @Order(30)
     public void generateSEI() throws Exception {
-        Generator generator = new ServiceInterfaceGenerator(ClassGeneratorFactory.class);
-        Class<?> newClass = EJBUtils.generateSEI(generator, loader);
+        Generator generator = new ServiceInterfaceGenerator(loader, ClassGeneratorFactory.class);
+        Class<?> newClass = EJBUtils.generateSEI(generator);
         assertNotNull(newClass);
         assertEquals(generator.getGeneratedClassName(), newClass.getName());
     }