=== modified file 'src/com/goldencode/p2j/persist/RecordBuffer.java'
--- old/src/com/goldencode/p2j/persist/RecordBuffer.java	2022-12-06 03:33:32 +0000
+++ new/src/com/goldencode/p2j/persist/RecordBuffer.java	2022-12-21 16:46:32 +0000
@@ -1243,6 +1243,8 @@
 **     CA  20221101          Accessing a setter while not in a TRANSACTION will raise error 7369.
 **     TJD 20220504          Upgrade do Java 11 minor changes
 **     OM  20221125          Added referenceOnly method.
+**     CA  20221212          Added support for a LambdaInvocationHandler which receives as arguments lambda 
+**                           expressions to perform a direct call of the target, and avoid reflection.
 */
 
 /*
@@ -11823,7 +11825,7 @@
     * purposes.
     */
    private final class Handler
-   implements InvocationHandler
+   implements LambdaInvocationHandler
    {
       /** Exception thrown during validation of no-undo temp-tables, which must be deferred */
       private ValidationException deferredValidationError = null;
@@ -11843,6 +11845,8 @@
        *          The target proxy object.
        * @param   method 
        *          The method to be executed.
+       * @param   f
+       *          A function to invoke as target, when specified.
        * @param   args 
        *          The method arguments.
        *
@@ -11851,7 +11855,11 @@
        * @throws  Throwable
        *          For various reasons, like illegal access to fields, illegal arguments or target.
        */
-      public Object invoke(Object proxy, Method method, Object[] args)
+      @Override
+      public Object invoke(Object proxy, 
+                           final Method method, 
+                           BiFunction<Object, Object[], Object> f, 
+                           Object[] args) 
       throws Throwable
       {
          Object result = null;
@@ -11867,7 +11875,7 @@
             Class<?> declClass = method.getDeclaringClass();
             if (declClass.equals(BufferReference.class) || declClass.equals(Object.class))
             {
-               return Utils.invoke(method, RecordBuffer.this, args);
+               return Utils.invoke(method, f, RecordBuffer.this, args);
             }
             
             // TODO: use something more reliable (but efficient) here to determine whether this is a setter
@@ -11889,6 +11897,9 @@
             // to ensure all validation and flushing is tracked properly
             if (creatingBuffer != null && currentRecord != null && isSetter)
             {
+               // this can't receive the lambdas, as they are statically linked with the this buffer's
+               // proxy types (a ClassCastException may be raised if the instance passed as first argument at
+               // the lambda is not of the expected type).
                return creatingBuffer.handler.invoke(proxy, method, args);
             }
             
@@ -11907,7 +11918,7 @@
             // if a temporary record is set, use it to back the invocation
             if (tempRecord != null)
             {
-               return Utils.invoke(method, tempRecord, args);
+               return Utils.invoke(method, f, tempRecord, args);
             }
             
             if (isSetter)
@@ -12101,7 +12112,7 @@
             }
             
             // invoke the method on the concrete DMO implementation
-            result = Utils.invoke(method, currentRecord, args);
+            result = Utils.invoke(method, f, currentRecord, args);
             
             if (writeSnapshot != null && !currentRecord.checkState(DmoState.CHANGED))
             {
@@ -12233,7 +12244,7 @@
                   if (!ok)
                   {
                      // the assign trigger vetoed: rolling back the change
-                     Utils.invoke(method, currentRecord, oldVal);
+                     Utils.invoke(method, f, currentRecord, oldVal);
                      processChange = false;
                   }
                }
@@ -12908,7 +12919,7 @@
     * {@link RecordBuffer} proxies.
     */
    private static class ArgumentBuffer
-   implements InvocationHandler
+   implements LambdaInvocationHandler
    {
       /** The backing buffer of this proxy, which should handle the majority of the methods */
       private BufferImpl buffer;
@@ -12998,7 +13009,11 @@
        * imply the DMO alias or buffer name, which will be handled here.
        */
       @Override
-      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+      public Object invoke(Object proxy, 
+                           final Method method, 
+                           BiFunction<Object, Object[], Object> f, 
+                           Object[] args)
+      throws Throwable
       {
          try 
          {
@@ -13019,7 +13034,7 @@
                if (method.getName().equals("overrideName") ||
                    method.getName().equals("restoreName"))
                {
-                  return Utils.invoke(method, buffer, args);
+                  return Utils.invoke(method, f, buffer, args);
                }
                
                boolean overridden = buffer.overrideName(bufferName);
@@ -13027,7 +13042,7 @@
                
                try
                {
-                  invokeReturn = Utils.invoke(method, buffer, args);
+                  invokeReturn = Utils.invoke(method, f, buffer, args);
                }
                finally
                {
@@ -13057,7 +13072,7 @@
                if (method.getName().equals("overrideDMOAlias") ||
                    method.getName().equals("restoreDMOAlias"))
                {
-                  return Utils.invoke(method, backBuffer, args);
+                  return Utils.invoke(method, f, backBuffer, args);
                }
                
                boolean overridden = backBuffer.overrideDMOAlias(dmoAlias);
@@ -13065,7 +13080,7 @@
                
                try
                {
-                  invokeReturn = Utils.invoke(method, backBuffer, args);
+                  invokeReturn = Utils.invoke(method, f, backBuffer, args);
                }
                finally
                {

=== modified file 'src/com/goldencode/p2j/persist/StaticDataSet.java'
--- old/src/com/goldencode/p2j/persist/StaticDataSet.java	2022-12-13 00:39:21 +0000
+++ new/src/com/goldencode/p2j/persist/StaticDataSet.java	2022-12-21 16:37:00 +0000
@@ -15,6 +15,8 @@
 **     OM  20211011 Improved debugging support for proxy objects.
 **     CA  20220707 Used a static 'doNotProxy' field, instead of creating the array each time.
 **     OM  20221206 Reworked REFERENCE-ONLY attribute.
+**     CA  20221212 Added support for a LambdaInvocationHandler which receives as arguments lambda expressions 
+**                  to perform a direct call of the target, and avoid reflection.
 */
 
 /*
@@ -77,6 +79,7 @@
 import com.goldencode.proxy.*;
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.function.*;
 
 
 /**
@@ -444,7 +447,7 @@
     * {@code DataSet} or will throw errors.
     */
    static class Handler
-   implements InvocationHandler
+   implements LambdaInvocationHandler
    {
       /**
        * Processes a method invocation on a proxy instance and returns the result. This method
@@ -458,6 +461,8 @@
        *          proxy instance. The declaring class of the {@code Method} object will be the
        *          interface that the method was declared in, which may be a superinterface of the
        *          proxy interface that the proxy class inherits the method through.
+       * @param   f
+       *          A function to invoke as target, when specified.
        * @param   args
        *          an array of objects containing the values of the arguments passed in the method
        *          invocation on the proxy instance, or {@code null} if interface method takes no
@@ -471,13 +476,16 @@
        * @see UndeclaredThrowableException
        */
       @Override
-      public Object invoke(Object proxy, Method method, Object[] args)
+      public Object invoke(Object proxy, 
+                           final Method method, 
+                           BiFunction<Object, Object[], Object> f, 
+                           Object[] args) 
       throws Throwable
       {
          StaticDataSet dsp = (StaticDataSet) proxy;
          if (dsp.bound != null)
          {
-            return Utils.invoke(method, dsp.bound, args);
+            return Utils.invoke(method, f, dsp.bound, args);
          }
          
          String[] errParam = new String[1];

=== modified file 'src/com/goldencode/p2j/persist/TemporaryBuffer.java'
--- old/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2022-12-13 00:39:21 +0000
+++ new/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2022-12-21 16:49:46 +0000
@@ -591,6 +591,8 @@
 **     OM  20221125          Handled BINDing of REFERENCE-ONLY OUTPUT buffers.
 **     AL2 20221205          Replaced AdaptiveQuery with PreselectQuery for loopDelete.
 **                           Use null sort instead of empty sort for PreselectQuery/
+**     CA  20221212          Added support for a LambdaInvocationHandler which receives as arguments lambda 
+**                           expressions to perform a direct call of the target, and avoid reflection.
 */
 
 /*
@@ -670,7 +672,7 @@
 import com.goldencode.p2j.util.*;
 import com.goldencode.p2j.util.ErrorManager;
 import com.goldencode.p2j.util.LogHelper;
-import com.goldencode.proxy.ProxyFactory;
+import com.goldencode.proxy.*;
 import com.goldencode.util.*;
 
 /**
@@ -8838,7 +8840,7 @@
     * The handler to switch between references, when binding a definition table to another one.
     */
    private static class ReferenceProxy
-   implements InvocationHandler
+   implements LambdaInvocationHandler
    {
       /** The default properties - PK and any other properties in {@link TempRecord}. */
       private static final Map<String, String> defaultProps;
@@ -8995,7 +8997,10 @@
        */
       @SuppressWarnings("deprecation")
       @Override
-      public Object invoke(Object proxy, Method method, Object[] args)
+      public Object invoke(Object proxy, 
+                           Method method, 
+                           BiFunction<Object, Object[], Object> f, 
+                           Object[] args) 
       throws Throwable
       {
          Object instance = (bound == null ? def : bound);
@@ -9018,7 +9023,7 @@
              declClass.equals(Object.class)          ||
              HandleResource.class.isAssignableFrom(declClass))
          {
-            return Utils.invoke(method, instance, args);
+            return Utils.invoke(method, f, instance, args);
          }
          
          if (bound != null && boundBuffer.getDMOInterface() != defBuffer.getDMOInterface())
@@ -9038,7 +9043,9 @@
                
                Method mbound = (setter ? boundSetterByProp.get(boundProperty) 
                                        : boundGetterByProp.get(boundProperty));
-               
+
+               // instance has switched
+               f = null;
                method = mbound;
             }
          }
@@ -9053,7 +9060,7 @@
                method.setAccessible(true);
             }
             
-            return Utils.invoke(method, instance, args);
+            return Utils.invoke(method, f, instance, args);
          }
          catch (Throwable t)
          {

=== modified file 'src/com/goldencode/p2j/util/ControlFlowOps.java'
--- old/src/com/goldencode/p2j/util/ControlFlowOps.java	2022-11-23 16:07:59 +0000
+++ new/src/com/goldencode/p2j/util/ControlFlowOps.java	2022-12-21 16:44:00 +0000
@@ -264,6 +264,7 @@
 **     TW  20221123          Augmented the error feedback, which omitted the target invocation name if
 **                           no parameters expected. Troubleshooting went haywire after that, since
 **                           root causes were sought at the wrong frame in the stack (refs: #6906).
+**     CA  20221220          Use lambdas to execute all public methods in an external program.
 */
 
 /*
@@ -948,6 +949,7 @@
             caller.callerInstance = reference;
             caller.wa = wa;
             caller.mthd = lastInvoke.method;
+            caller.lambda = lastInvoke.lambda;
             caller.methodName = lastInvoke.method.getName();
             caller.ie = null;
             caller.iename = cfg.getTarget();
@@ -994,7 +996,9 @@
 
                   try
                   {
-                     BaseDataType res = (BaseDataType) lastInvoke.method.invoke(reference, args);
+                     BaseDataType res = (BaseDataType) (lastInvoke.lambda == null 
+                                                         ? lastInvoke.method.invoke(reference, args)
+                                                         : lastInvoke.lambda.apply(reference, args));
                      res = checkInvokeResult(res, iename, cfg.isFunction(), cfg.isDynamicFunction());
                      
                      if (cls != null && cfg.isFunction())
@@ -8392,6 +8396,7 @@
       boolean externalProcedure = caller.getPhandle() == null;
       Object instance = externalProcedure ? caller.getClassName() : caller.getCallerInstance();
       Method mthd = externalProcedure ? null : caller.mthd;
+      BiFunction<Object, Object[], Object> lambda = externalProcedure ? null : caller.lambda;
       
       if (args != null && args.length > 0)
       {
@@ -8409,7 +8414,8 @@
                                                        eventProcedureName,
                                                        eventProcedureContext,
                                                        instance,
-                                                       mthd, 
+                                                       mthd,
+                                                       lambda,
                                                        argumentTypes);
       
       Map<InvokeConfig, LastInvokeDetails> thisCallSite = 
@@ -8455,6 +8461,11 @@
       private final Method method;
       
       /**
+       * When not-null, a lambda target to execute directly the call, without relying on the {@link #method}. 
+       */
+      private final BiFunction<Object, Object[], Object> lambda;
+      
+      /**
        * Create a new instance.
        * 
        * @param    legacyName
@@ -8474,6 +8485,9 @@
        *           {@link #method} is being invoked.
        * @param    method
        *           The Java method to invoke.
+       * @param    lambda
+       *           When not-null, a lambda target to execute directly the call, without relying on the 
+       *           {@link #method}. 
        * @param    argumentTypes
        *           The argument types for this call.
        */
@@ -8485,6 +8499,7 @@
                                Object     eventProcedureContext,
                                Object     reference,
                                Method     method,
+                               BiFunction<Object, Object[], Object> lambda,
                                Class<?>[] argumentTypes)
       {
          this.legacyName = legacyName;
@@ -8499,6 +8514,7 @@
          
          this.reference = (reference == null ? null : new WeakReference<>(reference));
          this.method = method;
+         this.lambda = lambda;
       }
       
       /**
@@ -8934,13 +8950,12 @@
       protected WorkArea wa;
       
       /** The {@link Method} instance for this internal entry. */
-      private Method mthd = null;
-      
-      /** The ReflectASM access point to this method. */
-      private MethodAccess access = null;
-      
-      /** The method index in the MethodAccess instance. */
-      private int index = -1;
+      protected Method mthd = null;
+      
+      protected BiFunction<Object, Object[], Object> lambda = null;
+      
+      /** Already resolved internal entry. */
+      protected InternalEntry ie = null;
       
       /** The handle associated with the {@link #callerInstance}. */
       private handle phandle;
@@ -8948,9 +8963,6 @@
       /** Worker which performs the {@link ProcedureManager.ProcedureHelper#pushCalleeInfo} call. */
       private Runnable pushWorker;
       
-      /** Already resolved internal entry (used when invoking OO methods). */
-      private InternalEntry ie = null;
-      
       /**
        * Basic c'tor.
        * 
@@ -9099,9 +9111,9 @@
             pushWorker.run();
             wa.bm.markPendingDynCall();
             
-            if (access != null)
+            if (lambda != null)
             {
-               return access.invoke(instance, index, param);
+               return lambda.apply(instance, param);
             }
             else
             {
@@ -9306,8 +9318,7 @@
                   if (value.method != null)
                   {
                      caller.mthd = value.method;
-                     caller.access = value.access;
-                     caller.index = value.index;
+                     caller.lambda = value.lambda;
                   }
                   
                   return value.returnValue;
@@ -9320,11 +9331,10 @@
                   method = cls.getMethod(caller.methodName, signature);
                   rv = ArgValidationErrors.NO_ERROR;
                   
-                  value = putCache(key, method, rv, true);
+                  value = putCache(key, method, null, rv, true);
 
                   caller.mthd = value.method;
-                  caller.access = value.access;
-                  caller.index = value.index;
+                  caller.lambda = value.lambda;
                   
                   return rv;
                }
@@ -9339,11 +9349,10 @@
                   method = cls.getDeclaredMethod(caller.methodName, signature);
                   rv = ArgValidationErrors.NO_ERROR;
                   
-                  value = putCache(key, method, rv, true);
+                  value = putCache(key, method, null, rv, true);
                   
                   caller.mthd = value.method;
-                  caller.access = value.access;
-                  caller.index = value.index;
+                  caller.lambda = value.lambda;
 
                   return rv;
                }
@@ -9541,7 +9550,7 @@
                   extentInfo[0] = parExtent ? paramExtent : 0;
                   
                   // cache failed result as well, so we don't need to repeat validation
-                  putCache(key, null, rv, true);
+                  putCache(key, null, null, rv, true);
                   
                   return rv;
                }
@@ -9961,12 +9970,11 @@
                
                if (value == null)
                {
-                  value = putCache(key, m, rv, false);
+                  value = putCache(key, m, m.equals(caller.mthd) ? caller.lambda : null, rv, false);
                }
                
                caller.mthd = value.method;
-               caller.access = value.access;
-               caller.index = value.index;
+               caller.lambda = value.lambda;
                
                return rv;
             }
@@ -9979,7 +9987,7 @@
               : ArgValidationErrors.INCORRECT_TYPES;
          
          // cache failed result as well, so we don't need to repeat validation
-         putCache(key, null, rv, true);
+         putCache(key, null, null, rv, true);
          
          return rv;
       }
@@ -10115,6 +10123,8 @@
        * @param   method
        *          Method found matching a given name and signature, or {@code null} if no
        *          match was found.
+       * @param   lambda
+       *          When not-null, a lambda target to execute directly the call, without relying on the method. 
        * @param   returnValue
        *          Enumerated return value for {@link #valid(boolean, String, int[], Object...)}
        *          method.
@@ -10126,11 +10136,12 @@
        * @return  the created cache.
        */
       private static CacheValue putCache(CacheKey key,
-                                  Method method,
-                                  ArgValidationErrors returnValue,
-                                  boolean exactMatch)
+                                         Method method,
+                                         BiFunction<Object, Object[], Object> lambda,
+                                         ArgValidationErrors returnValue,
+                                         boolean exactMatch)
       {
-         CacheValue value = new CacheValue(method, returnValue, exactMatch);
+         CacheValue value = new CacheValue(method, lambda, returnValue, exactMatch);
          
          synchronized (cache)
          {
@@ -10260,11 +10271,11 @@
          /** Method, if any, else <code>null</code> if none was found */
          final Method method;
 
-         /** The ReflectASM access point to this method. */
-         final MethodAccess access;
-         
-         /** The method index in the MethodAccess instance. */
-         final int index;
+         /**
+          * When not-null, a lambda target to execute directly the call, without relying on the 
+          * {@link #method}. 
+          */
+         final BiFunction<Object, Object[], Object> lambda;
          
          /** 
           * Enumerated return value for {@link 
@@ -10280,6 +10291,9 @@
           * 
           * @param   method
           *          Method, if any, else <code>null</code> if none was found.
+          * @param   lambda
+          *          When not-null, a lambda target to execute directly the call, without relying on the 
+          *          {@link #method}. 
           * @param   returnValue
           *          Enumerated return value for {@link
           *          InternalEntryCaller#valid(boolean, String, int[], Object...)}.
@@ -10287,27 +10301,10 @@
           *          Flag indicating whether signature of caller's parameters exactly matches
           *          method.
           */
-         CacheValue(Method method, ArgValidationErrors returnValue, boolean exactMatch)
+         CacheValue(Method method, BiFunction<Object, Object[], Object> lambda, ArgValidationErrors returnValue, boolean exactMatch)
          {
             this.method = method;
-            if (method != null)
-            {
-               if (!Modifier.isPrivate(method.getModifiers()))
-               {
-                  this.access = MethodAccess.get(method.getDeclaringClass());
-                  this.index = access.getIndex(method.getName(), method.getParameterTypes());
-               }
-               else
-               {
-                  this.access = null;
-                  this.index = -1;
-               }
-            }
-            else
-            {
-               this.access = null;
-               this.index = -1;
-            }
+            this.lambda = lambda;
             this.returnValue = returnValue;
             this.exactMatch = exactMatch;
          }
@@ -10511,6 +10508,8 @@
        * 
        * @param    wa
        *           The context-local state in {@link WorkArea}.
+       * @param    name
+       *           The external program name.
        * @param    className
        *           The class name associated with the external program.
        * @param    persistent
@@ -10519,10 +10518,14 @@
        * @throws   Exception
        *           If the class can't be resolved. 
        */
-      public ExternalProcedureCaller(WorkArea wa, String className, boolean persistent)
+      public ExternalProcedureCaller(WorkArea wa, String name, String className, boolean persistent)
       throws Exception
       {
          super(wa);
+
+         this.ie = SourceNameMapper.getInternalEntry(name, null, false);
+         this.mthd = (ie == null ? null : ie.getMethod());
+         this.lambda = (ie == null ? null : ie.getLambda());
          
          this.methodName = "execute";
          this.className = className;
@@ -10729,7 +10732,12 @@
                wa.currentInvoke = null;
                res = new MapToNotFound(wa, mapTo);
             }
-            
+            else
+            {
+               res.mthd = ie.getMethod();
+               res.lambda = ie.getLambda();
+            }
+
             res.ie = ie;
             return res;
          }
@@ -10747,6 +10755,8 @@
             
             caller = new InternalEntryCaller(wa, hcaller, ie.jname, ieName);
             caller.ie = ie;
+            caller.mthd = ie.getMethod();
+            caller.lambda = ie.getLambda();
          }
          /*
          else if (!superCall)
@@ -10939,7 +10949,7 @@
                // name to any errors generated during instantiation (i.e. shared vars error msgs 
                // need to know the procedure name where they are defined, if an error happens)
                wa.pm.setInstantingExternalProgram(name);
-               caller = new ExternalProcedureCaller(wa, className, persistent);
+               caller = new ExternalProcedureCaller(wa, name, className, persistent);
             }
             catch (Throwable t)
             {

=== modified file 'src/com/goldencode/p2j/util/InternalEntry.java'
--- old/src/com/goldencode/p2j/util/InternalEntry.java	2021-02-21 14:39:08 +0000
+++ new/src/com/goldencode/p2j/util/InternalEntry.java	2022-12-21 16:40:49 +0000
@@ -30,6 +30,8 @@
 ** 015 CA  20200605 The Java method instance is resolved on first access of getMethod().
 ** 016 ME  20200810 Added qualified name support in signature processing.
 **     CA  20210218 Fixed signature processing for qualified return type.
+**     CA  20221220 Use lambdas to execute all public methods in an external program.  Fixed synchronization
+**                  in getMethod() and getLambda(), when calling SourceNameMapper.buildLegacyProgram.
 */
 
 /*
@@ -89,6 +91,7 @@
 
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.function.*;
 
 import com.goldencode.p2j.util.SourceNameMapper.ExternalProgram;
 
@@ -268,19 +271,19 @@
     * Flag indicating if this is a IN SUPER internal entry (when set to <code>true</code>).
     * Gets its permanent value when internal entry is initialized by {@link SourceNameMapper}.
     */
-   private Boolean isSuper = null;
+   private boolean isSuper = false;
    
    /** 
     * Flag indicating if this is a IN handle internal entry (when set to <code>true</code>).
     * Gets its permanent value when internal entry is initialized by {@link SourceNameMapper}.
     */
-   private Boolean inHandle = null;
+   private boolean inHandle = false;
    
    /** 
     * Flag indicating if this is a PRIVATE internal entry (when set to <code>true</code>).
     * Gets its permanent value when internal entry is initialized by {@link SourceNameMapper}.
     */
-   private Boolean isPrivate = null;
+   private boolean isPrivate = false;
    
    /** The return type's extent. */
    private int extent = SourceNameMapper.NO_EXTENT;
@@ -293,6 +296,9 @@
     */
    private Method method = null;
    
+   /** When not-null, represents a lambda function to execute directly the target. */
+   private BiFunction<Object, Object[], Object> lambda = null;
+   
    /** The OS library name, if this is a native method. */
    private String libname = null;
    
@@ -451,19 +457,44 @@
     */
    public Method getMethod()
    {
-      if (method == null && extprog != null && extprog.ooname == null)
+      if (method == null && extprog != null && extprog.buildLegacy && extprog.ooname == null)
       {
-         SourceNameMapper.buildLegacyProgram(extprog);
-         
-         // in case the Java method is not needed for this entry (is a in-handle or in-super), avoid multiple 
-         // lookups.
-         extprog = null;
+         synchronized (extprog)
+         {
+            if (extprog.buildLegacy)
+            {
+               SourceNameMapper.buildLegacyProgram(extprog);
+               extprog.buildLegacy = false;
+            }
+         }
       }
       
       return method;
    }
    
    /**
+    * Get the lambda target to be executed, see {@link #lambda}.
+    * 
+    * @return   See above.
+    */
+   public BiFunction<Object, Object[], Object> getLambda()
+   {
+      if (method == null && extprog != null && extprog.buildLegacy && extprog.ooname == null)
+      {
+         synchronized (extprog)
+         {
+            if (extprog.buildLegacy)
+            {
+               SourceNameMapper.buildLegacyProgram(extprog);
+               extprog.buildLegacy = false;
+            }
+         }
+      }
+      
+      return lambda;
+   }
+   
+   /**
     * Get the value of the given attribute.  If the attribute is null or
     * is not set, return <code>null</code>.
     * 
@@ -580,6 +611,17 @@
    }
    
    /**
+    * Set the target lambda for this internal entry to the specified one.
+    * 
+    * @param    lambda
+    *           The target lambda.
+    */
+   void setLambda(BiFunction<Object, Object[], Object> lambda)
+   {
+      this.lambda = lambda;
+   }
+   
+   /**
     * Set the external program for this entry.
     * 
     * @param    extprog

=== modified file 'src/com/goldencode/p2j/util/SourceNameMapper.java'
--- old/src/com/goldencode/p2j/util/SourceNameMapper.java	2022-12-15 19:51:31 +0000
+++ new/src/com/goldencode/p2j/util/SourceNameMapper.java	2022-12-21 16:39:47 +0000
@@ -143,6 +143,7 @@
 **     TJD 20220823          Prevent recursive calls to initMappingData() workaround
 **     TJD 20220824          Prevent recursive calls to initMappingData() workaround in more effective way
 **     SBI 20221215          Filter the same REST java methods having erased parameters types.
+**     CA  20221220          Use lambdas to execute all public methods in an external program.
 */
 
 /*
@@ -216,6 +217,7 @@
 import com.goldencode.p2j.oo.lang.*;
 import com.goldencode.p2j.rest.*;
 import com.goldencode.p2j.soap.*;
+import com.goldencode.proxy.*;
 import com.goldencode.p2j.security.*;
 
 /**
@@ -2897,6 +2899,8 @@
          throw new RuntimeException(e);
       }
 
+      Map<Method, BiFunction<Object, Object[], Object>> lambdas = LambdaFactory.buildLambdas(cls);
+      
       Method[] methods = cls.getDeclaredMethods();
       for (Method mthd : methods)
       {
@@ -2922,6 +2926,12 @@
             if (ie != null)
             {
                ie.setMethod(mthd);
+               
+               if (lambdas != null)
+               {
+                  BiFunction<Object, Object[], Object> lambda = lambdas.get(mthd);
+                  ie.setLambda(lambda);
+               }
             }
          }
       }
@@ -3334,6 +3344,12 @@
       InternalEntry main = null;
       
       /**
+       * Flag indicating if {@link SourceNameMapper#buildLegacyClass(Class)} needs to be called when 
+       * {@link InternalEntry#getMethod()} or {@link InternalEntry#getLambda()} are accessed.
+       */
+      boolean buildLegacy = true;
+      
+      /**
        * Basic c'tor.
        * 
        * @param    pname

=== modified file 'src/com/goldencode/p2j/util/Utils.java'
--- old/src/com/goldencode/p2j/util/Utils.java	2022-10-28 10:54:33 +0000
+++ new/src/com/goldencode/p2j/util/Utils.java	2022-12-21 16:37:39 +0000
@@ -185,6 +185,8 @@
 **     SBI 20220504          Fixed toChar(int, String) to return -1 if key code is not represented by
 **                           the given char set.
 **     TJD 20220504          Java 11 compatibility minor changes
+**     CA  20221212          Added support for a LambdaInvocationHandler which receives as arguments lambda 
+**                           expressions to perform a direct call of the target, and avoid reflection.
 */
 
 /*
@@ -1602,6 +1604,45 @@
     * More, the maps are identity-keyed, for fast access.
     * 
     * @param    method
+    *           The method to execute, only if the function or consumer are both null.
+    * @param    f
+    *           When not-null, invoke this function and return its value.
+    * @param    instance
+    *           The instance on which the call will be made; can be <code>null</code> for static methods.
+    * @param    args
+    *           The method's arguments.
+    *           
+    * @return   The method's return value.
+    * 
+    * @throws   IllegalAccessException
+    * @throws   IllegalArgumentException
+    * @throws   InvocationTargetException
+    */
+   public static Object invoke(Method method, 
+                               BiFunction<Object, Object[], Object> f, 
+                               Object instance, 
+                               Object... args) 
+   throws IllegalAccessException, 
+          IllegalArgumentException, 
+          InvocationTargetException
+    {
+      if (f != null)
+      {
+         return f.apply(instance, args);
+      }
+      else
+      {
+         return invoke(method, instance, args);
+      }
+    }
+   
+   /**
+    * Invoke the specified {@link Method} using ReflectASM instead of standard reflection.
+    * <p>
+    * ReflectASM related data is cached in {@link #METHOD_DATA}, thread-local, to avoid the concurrent access.
+    * More, the maps are identity-keyed, for fast access.
+    * 
+    * @param    method
     *           The method to execute.
     * @param    instance
     *           The instance on which the call will be made; can be <code>null</code> for static methods.

=== added file 'src/com/goldencode/proxy/DefaultHandlerPlugin.java'
--- old/src/com/goldencode/proxy/DefaultHandlerPlugin.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/DefaultHandlerPlugin.java	2022-12-12 15:05:06 +0000
@@ -0,0 +1,129 @@
+/*
+** Module   : DefaultHandlerPlugin.java
+** Abstract : 
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
+** 001 CA  20221212 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.lang.reflect.*;
+
+import org.objectweb.asm.*;
+
+import com.goldencode.asm.AsmUtils;
+
+/**
+ * Assembler for the invocation arguments emitted for the {@link InvocationHandler#invoke} method.
+ */
+class DefaultHandlerPlugin
+implements InvocationHandlerPlugin
+{
+   /**
+    * Get the handler's class.
+    * 
+    * @return   {@link InvocationHandler} type.
+    */
+   @Override
+   public Class<? extends InvocationHandler> getHandlerClass()
+   {
+      return InvocationHandler.class;
+   }
+
+   /**
+    * Get the signature of the 'invoke' method for the {@link InvocationHandler}.
+    */
+   @Override
+   public String getInvokeSignature()
+   {
+      return "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
+   }
+
+   /**
+    * Create the arguments related to invoking the target of this proxied call.  This will emit a {@link Method}
+    * reference from within the 'ma' array at the specified 'methodIndex'.
+    * 
+    * @param    classWriter
+    *           Class writer for proxy class.
+    * @param    mv
+    *           Method visitor for this method.
+    * @param    proxyName
+    *           Internal form of the proxy class' name.
+    * @param    method
+    *           Method for which this proxy is being implemented.
+    * @param    methodIndex
+    *           Index of this method within the array of methods used by the invocation handler.
+    */
+   @Override
+   public void createInvocationArgs(ClassWriter   classWriter, 
+                                    MethodVisitor mv, 
+                                    String        proxyName, 
+                                    Method        method, 
+                                    int           methodIndex)
+   {
+      // load target method from array of methods in static field "ma"
+      mv.visitFieldInsn(ProxyAssembler.GETSTATIC,
+                        proxyName,
+                        "ma",
+                        "[Ljava/lang/reflect/Method;");
+      
+      // target method is at index "index" in the "ma" array
+      AsmUtils.pushInt(mv, methodIndex);
+      mv.visitInsn(Opcodes.AALOAD);
+  }
+}
\ No newline at end of file

=== added file 'src/com/goldencode/proxy/InvocationHandlerPlugin.java'
--- old/src/com/goldencode/proxy/InvocationHandlerPlugin.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/InvocationHandlerPlugin.java	2022-12-12 15:27:10 +0000
@@ -0,0 +1,106 @@
+/*
+** Module   : InvocationHandlerPlugin.java
+** Abstract : 
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
+** 001 CA  20221212 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.lang.reflect.*;
+
+import org.objectweb.asm.*;
+
+/**
+ * Assembler for the invocation arguments emitted for the 'invoke' method at the handler.
+ */
+public interface InvocationHandlerPlugin
+{
+   /**
+    * Get the handler's class.
+    * 
+    * @return   A sub-class of {@link InvocationHandler}.
+    */
+   public Class<? extends InvocationHandler> getHandlerClass();
+
+   /**
+    * Get the signature of the 'invoke' method for the {@link #getHandlerClass() handler type}.
+    */
+   public String getInvokeSignature();
+
+   /**
+    * Create the arguments related to invoking the target of this proxied call.  This will emit at least the
+    * {@link Method} reference.
+    * 
+    * @param    classWriter
+    *           Class writer for proxy class.
+    * @param    mv
+    *           Method visitor for this method.
+    * @param    proxyName
+    *           Internal form of the proxy class' name.
+    * @param    method
+    *           Method for which this proxy is being implemented.
+    * @param    methodIndex
+    *           Index of this method within the array of methods used by the invocation handler.
+    */
+   public void createInvocationArgs(ClassWriter   classWriter, 
+                                    MethodVisitor mv, 
+                                    String        proxyName, 
+                                    Method        method, 
+                                    int           methodIndex);
+}

=== added file 'src/com/goldencode/proxy/LambdaAssembler.java'
--- old/src/com/goldencode/proxy/LambdaAssembler.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/LambdaAssembler.java	2022-12-20 11:02:28 +0000
@@ -0,0 +1,477 @@
+/*
+** Module   : LambdaAssembler.java
+** Abstract : Assembles a dynamic class which defines lambdas for all reachable public methods in a certain 
+**            type.
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- --------------------------------Description----------------------------------
+** 001 CA  20221220 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.function.*;
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.Type;
+
+import com.goldencode.asm.*;
+
+/**
+ * A class which assembles dynamic types defining lambda functions for all public, non-static, methods of
+ * that type (and its super-classes and super-interfaceS).  This is done using the ASM bytecode engineering 
+ * library, v5.0.4 (http://asm.ow2.org).  As a package private class, it is intended to be invoked only by the 
+ * {@link LambadFactory}, which exposes a public API for the definition of new proxy objects.
+ * <p>
+ * This mechanism is used to replace Java reflection (via {@link Method#invoke(Object, Object...)} or 
+ * ReflectASM, to perform dynamic calls.
+ * <p>
+ * The following pseudo-code representation is intended to convey the general structure of the generated type. 
+ *  However, please note that no intermediate source code representation is produced.
+ * <p>
+ * <pre>
+ * public final class $__[type]Lambdas 
+ * {
+ *    // the mapping of Method instances to the BiFunction lambda
+ *    private static final HashMap lambdas = new HashMap();
+ *    
+ *    // get the 'lambdas' map.
+ *    public static Map getLambdas() 
+ *    {
+ *       return lambdas;
+ *    }
+ *    
+ *    static
+ *    {
+ *       try
+ *       {
+ *          Method m = [type].class.getDeclaredMethod("[method]", [arg types...]);
+ *          lambdas.put(m, (ref, args) -> { return (([type]) ref).[method](args[0], args[1], ...); });
+ *          ...
+ *          // each method in the given type
+ *          ...
+ *       }
+ *       catch (Throwable t)
+ *       {
+ *          throw new RuntimeException(t);
+ *       }
+ *    }
+ * }
+ * </pre>
+ */
+class LambdaAssembler
+implements Opcodes
+{
+   /** The name of the static map holding the lambdas. */
+   private static final String FIELD_LAMBDAS = "lambdas";
+   
+   /** Object used to create class fields, methods, etc. */
+   private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | 
+                                                           ClassWriter.COMPUTE_MAXS);
+   
+   /** The name of the type where the lambdas will be defined. */
+   private final String typeName;
+   
+   /** The methods which require lambda definitions. */
+   private final HashSet<Method> methods;
+
+   /** A counter for the number of lambdas defined in this type. */
+   private int lambdaNum = 0;
+   
+   /**
+    * Constructor.
+    * 
+    * @param    typeName
+    *           The name of the type where the lambdas will be defined.
+    * @param    methods
+    *           The methods which require lambda definitions.
+    */
+   LambdaAssembler(String typeName, HashSet<Method> methods)
+   {
+      this.typeName = AsmUtils.commonToInternalTypeName(typeName);
+      this.methods = methods;
+   }
+
+   /**
+    * Assemble the class in accordance with the Java class file format as specified in <u>The Java Virtual 
+    * Machine Specification, Second Edition</u> by Tim Lindholm and Frank Yellin.
+    * <p>
+    * See the class description above for details regarding the content of the assembled class.
+    * 
+    * @return   Byte array containing the class definition.
+    */
+   public byte[] assembleClass()
+   {
+      // create the dynamic class
+      classWriter.visit(V1_8,
+                        ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
+                        typeName,
+                        null,
+                        "java/lang/Object",
+                        null);
+      
+      // add a class member field for the lambda map
+      classWriter.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL,
+                             FIELD_LAMBDAS,
+                             "Ljava/util/HashMap;",
+                             null,
+                             null);
+      
+      assembleLambdaGetter();
+      
+      assembleLambdas();
+      
+      // complete the assembly
+      classWriter.visitEnd();
+
+      // get the byte array that represents the class file
+      byte[] code = classWriter.toByteArray();
+
+      return code;
+   }
+
+   /**
+    * Emit the bytecode for the lambda call.
+    * 
+    * @param    typeName
+    *           The type where this lambda is defined.
+    * @param    method
+    *           The target method.
+    * @param    lambdaName
+    *           The name of this synthetic lambda method.
+    * @param    classWriter
+    *           Class writer for proxy class.
+    * @param    mv
+    *           Method writer, where this lambda is being invoked.
+    */
+   public static void emitLambdaCall(String        typeName, 
+                                     Method        method, 
+                                     String        lambdaName, 
+                                     ClassWriter   classWriter, 
+                                     MethodVisitor mv)
+   {
+      String retType = "Ljava/lang/Object;";
+      
+      Object[] mthdArgs = 
+      { 
+         Type.getMethodType("(Ljava/lang/Object;Ljava/lang/Object;)" + retType),
+         new Handle(H_INVOKESTATIC, 
+                    typeName, 
+                    lambdaName, 
+                    "(Ljava/lang/Object;[Ljava/lang/Object;)" + retType),
+                    Type.getMethodType("(Ljava/lang/Object;[Ljava/lang/Object;)" + retType)
+      };
+      
+      Handle h = new Handle(H_INVOKESTATIC, 
+                            "java/lang/invoke/LambdaMetafactory", 
+                            "metafactory", 
+                            "(Ljava/lang/invoke/MethodHandles$Lookup;" + 
+                            "Ljava/lang/String;Ljava/lang/invoke/MethodType;" +
+                            "Ljava/lang/invoke/MethodType;" +
+                            "Ljava/lang/invoke/MethodHandle;" +
+                            "Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"
+                            );
+
+      mv.visitInvokeDynamicInsn("apply", "()Ljava/util/function/BiFunction;", h, mthdArgs);
+      
+      Class<?> clazz = method.getDeclaringClass();
+      if (clazz.isAnonymousClass())
+      {
+         classWriter.visitInnerClass(AsmUtils.commonToInternalTypeName(clazz.getName()), 
+                                     AsmUtils.commonToInternalTypeName(clazz.getDeclaringClass().getName()), 
+                                     clazz.getSimpleName(), 
+                                     clazz.getModifiers());
+      }
+      classWriter.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", 
+                                  "java/lang/invoke/MethodHandles", 
+                                  "Lookup", 
+                                  ACC_PUBLIC | ACC_STATIC | ACC_FINAL);
+   }
+
+   /**
+    * Emit a the bytecode for the synthetic lambda method.  This will perform the actual Java method call, 
+    * by using the first lambda argument as the reference (in case of instance methods) and emiting the 
+    * arguments from the second <code>Object[]</code> lambda argument.
+    * <p>
+    * Arguments for Java native type parameters are automatically unwrapped.
+    *  
+    * @param    classWriter
+    *           Class writer for proxy class.
+    * @param    lambdaName
+    *           The name of this synthetic lambda method.
+    * @param    method
+    *           Method for which this proxy is being implemented.
+    */
+   static void emitLambdaMethod(ClassWriter classWriter, String lambdaName, Method method)
+   {
+      boolean isVoid = method.getReturnType() == void.class;
+      
+      String desc = "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;";
+      
+      MethodVisitor mv = classWriter.visitMethod(ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, 
+                                                 lambdaName, 
+                                                 desc, 
+                                                 null,
+                                                 new String[0]);
+      mv.visitCode();
+      
+      int maxStack = 0;
+      
+      {
+         Class<?> clazz = method.getDeclaringClass();
+         String clazzDesc = AsmUtils.commonToInternalTypeName(clazz);
+         // TODO: null instances (static methods)
+         mv.visitVarInsn(ALOAD, 0);
+         mv.visitTypeInsn(CHECKCAST, clazzDesc);
+         
+         Class<?>[] parmTypes = method.getParameterTypes();
+         for (int i = 0; i < parmTypes.length; i++)
+         {
+            TypeInfo parmInfo = ProxyUtils.getTypeInfo(method.getParameterTypes()[i]);
+
+            maxStack += parmInfo.getWidth();
+            
+            mv.visitVarInsn(ALOAD, 1);
+            AsmUtils.pushInt(mv, i);
+            mv.visitInsn(AALOAD);
+            
+            MethodInfo unwrapInfo = parmInfo.getUnwrapInfo();
+            String castName = parmInfo.getCastName();
+            if (castName != null && !"java/lang/Object".equals(castName))
+            {
+               mv.visitTypeInsn(CHECKCAST, parmInfo.getCastName());
+            }
+            
+            if (unwrapInfo != null)
+            {
+               mv.visitMethodInsn(INVOKEVIRTUAL,
+                                  unwrapInfo.getClassName(),
+                                  unwrapInfo.getMethodName(),
+                                  unwrapInfo.getDescriptor(),
+                                  false);
+            }
+         }
+         desc = ProxyUtils.makeMethodDescriptor(method);
+         boolean isStatic = Modifier.isStatic(method.getModifiers());
+         boolean isIFace = clazz.isInterface();
+         boolean isAbstract = Modifier.isAbstract(method.getModifiers());
+         boolean isPublic = Modifier.isPublic(method.getModifiers());
+         mv.visitMethodInsn(isStatic ? INVOKESTATIC : isIFace ? INVOKEINTERFACE : INVOKEVIRTUAL, 
+                            clazzDesc, 
+                            method.getName(), 
+                            desc, 
+                            isIFace);
+         
+         if (isVoid)
+         {
+            mv.visitInsn(ACONST_NULL);
+         }
+         else
+         {
+            TypeInfo retInfo = ProxyUtils.getTypeInfo(method.getReturnType());
+            MethodInfo wrapInfo = retInfo.getWrapInfo();
+            if (wrapInfo != null)
+            {
+               mv.visitMethodInsn(INVOKESTATIC,
+                                  wrapInfo.getClassName(),
+                                  wrapInfo.getMethodName(),
+                                  wrapInfo.getDescriptor(),
+                                  false);
+            }
+         }
+         
+         mv.visitInsn(ARETURN);
+      }
+      
+      mv.visitMaxs(maxStack, 2);
+      mv.visitEnd();
+   }
+
+   /**
+    * Assemble the <code>getLambdas</code> public, static, method, which returns the {@link #FIELD_LAMBDAS} 
+    * map.
+    */
+   private void assembleLambdaGetter()
+   {
+      MethodVisitor mv =
+               classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC,
+                                       "getLambdas",
+                                       "()Ljava/util/Map;",
+                                       null,
+                                       null);
+
+      // get the current value of the "lambdas" static field
+      mv.visitFieldInsn(GETSTATIC,
+                        typeName,
+                        FIELD_LAMBDAS,
+                        "Ljava/util/HashMap;");
+      
+      mv.visitInsn(ARETURN);
+      
+      mv.visitMaxs(0, 0);
+      mv.visitEnd();
+   }
+
+   /**
+    * Assemble all lambdas, to populate the 'lambdas' map.  This will create a static constructor definition
+    * where, for each {@link #methods method}, the lambda is created and put in the map.
+    * <p>
+    * All lambdas are a {@link BiFunction}, with <code>Object</code> as first type (the reference on which the
+    * target method is being invoked), and a <code>Object[]</code> second type, with the arguments to be 
+    * passed to the method call.
+    */
+   private void assembleLambdas()
+   {
+      // create the class static constructor
+      MethodVisitor mv = classWriter.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+      
+      Label tryLblStart = new Label();
+      Label tryLblEnd = new Label();
+      Label catchLblStart = new Label();
+      Label catchLblEnd = new Label();
+      Label tryBlock = new Label();
+
+      Label mlblStart = tryLblStart;
+      Label mlblEnd = tryLblEnd;
+      Label tlblStart = catchLblStart;
+      Label tlblEnd = catchLblEnd;
+      
+      mv.visitLabel(new Label());
+      // initialize the 'lambdas' static field
+      mv.visitTypeInsn(NEW, "java/util/HashMap");
+      mv.visitInsn(DUP);
+      mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false);
+      mv.visitFieldInsn(PUTSTATIC, typeName, FIELD_LAMBDAS, "Ljava/util/HashMap;");
+      
+      mv.visitLabel(tryLblStart);
+      for (Method m : methods)
+      {
+         String declaringName = m.getDeclaringClass().getName();
+         declaringName = AsmUtils.commonToInternalTypeName(declaringName);
+         mv.visitLdcInsn(Type.getObjectType(declaringName));
+         mv.visitLdcInsn(m.getName());
+         int numArgs = m.getParameterCount();
+         AsmUtils.pushInt(mv, numArgs);
+         mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
+         
+         // emit arguments
+         Class<?>[] parmTypes = m.getParameterTypes();
+         for (int i = 0; i < numArgs; i++)
+         {
+            mv.visitInsn(DUP);
+            AsmUtils.pushInt(mv, i);
+            mv.visitLdcInsn(Type.getObjectType(AsmUtils.commonToInternalTypeName(parmTypes[i])));
+            mv.visitInsn(AASTORE);
+         }
+         
+         mv.visitMethodInsn(INVOKEVIRTUAL, 
+                            "java/lang/Class", 
+                            "getDeclaredMethod", 
+                            "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", 
+                            false);
+         mv.visitIntInsn(ASTORE, 0);
+         
+         // put the lambda into the map
+         mv.visitFieldInsn(GETSTATIC, typeName, FIELD_LAMBDAS, "Ljava/util/HashMap;");
+         mv.visitIntInsn(ALOAD, 0);
+         
+         String lambdaName = "lambda$" + (lambdaNum++);
+         emitLambdaMethod(classWriter, lambdaName, m);
+         emitLambdaCall(typeName, m, lambdaName, classWriter, mv);
+         
+         mv.visitMethodInsn(INVOKEVIRTUAL, 
+                            "java/util/HashMap", 
+                            "put", 
+                            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 
+                            false);
+         mv.visitInsn(POP);
+      }
+      
+      mv.visitLabel(tryLblEnd);
+      mv.visitJumpInsn(GOTO, catchLblEnd);
+      
+      // emit the try block
+      mv.visitLabel(tryBlock);
+      mv.visitFrame(F_NEW, 0, null, 1, new Object[] { "java/lang/Throwable" });
+      mv.visitVarInsn(ASTORE, 1);
+      mv.visitLabel(catchLblStart);
+      mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+      mv.visitInsn(DUP);
+      mv.visitVarInsn(ALOAD, 1);
+      mv.visitMethodInsn(INVOKESPECIAL, 
+                         "java/lang/RuntimeException", 
+                         "<init>", 
+                         "(Ljava/lang/Throwable;)V", 
+                         false);
+      mv.visitInsn(ATHROW);
+      mv.visitLabel(catchLblEnd);
+      
+      mv.visitFrame(F_NEW, 0, new Object[0], 0, new Object[0]);
+      mv.visitInsn(RETURN);
+      
+      mv.visitLocalVariable("m", "Ljava/lang/reflect/Method;", null, mlblStart, mlblEnd, 0);
+      
+      mv.visitLocalVariable("t", "Ljava/lang/Throwable;", null, tlblStart, tlblEnd, 1);
+      
+      mv.visitTryCatchBlock(tryLblStart, tryLblEnd, tryBlock, "java/lang/Throwable");
+
+      mv.visitMaxs(1, 2);
+
+      mv.visitEnd();
+   }
+}

=== added file 'src/com/goldencode/proxy/LambdaFactory.java'
--- old/src/com/goldencode/proxy/LambdaFactory.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/LambdaFactory.java	2022-12-20 14:46:30 +0000
@@ -0,0 +1,230 @@
+/*
+** Module   : LambdaFactory.java
+** Abstract : Utility class to create lambda functions for all public methods accessible from a type.
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- --------------------------------------Description-----------------------------------------
+** 001 CA  20221220 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.function.*;
+
+import com.goldencode.asm.*;
+
+/**
+ * Builds a runtime-generated type which defines lambdas for all public, non-static methods accessible from
+ * a given type and all its super-classes and super-interfaces.
+ * <p>
+ * These lambdas are added into a static class field, of type 
+ * <code>Map<Method, BiFunction<Object, Object[], Object>></code>, and this map is populated in the class
+ * static constructor.
+ * <p>
+ * A single <code>public static Map<Method, BiFunction<Object, Object[], Object>> getLambdas()</code> method
+ * is defined in each type, which returns the map populated in the static constructor.  This map is returned
+ * as a direct reference, callers of {@link #buildLambdas(Class)} must not modify this instance.
+ */
+public class LambdaFactory
+{
+   /** Custom class loader to load proxy classes */
+   private static final AsmClassLoader loader = AsmClassLoader.getInstance();
+   
+   /** Singleton instance of this factory class */
+   private static final LambdaFactory singleton = new LambdaFactory();
+   
+   /**
+    * Private constructor to ensure singleton instance.
+    */
+   private LambdaFactory()
+   {
+   }
+   
+   /**
+    * For a given type, generate the dynamic type which defines the lambda functions for all public methods,
+    * and return a map with the {@link Method} and the associated {@link BiFunction}.
+    * 
+    * @param    type
+    *           The type which needs created lambdas.
+    *           
+    * @return   See above.
+    */
+   public static Map<Method, BiFunction<Object, Object[], Object>> buildLambdas(Class<?> type)
+   {
+      return singleton.buildLambdasImpl(type);
+   }
+   
+   /**
+    * For a given type, generate the dynamic type which defines the lambda functions for all public methods,
+    * and return a map with the {@link Method} and the associated {@link BiFunction}.
+    * 
+    * @param    type
+    *           The type which needs created lambdas.
+    *           
+    * @return   See above.
+    */
+   private Map<Method, BiFunction<Object, Object[], Object>> buildLambdasImpl(Class<?> type)
+   {
+      String pkg = type.getPackage().getName();
+      String typeName =  (pkg == null ? "" : pkg + ".") + "$__" + type.getSimpleName() + "Lambdas";
+      
+      synchronized (this)
+      {
+         Class<?> clazz = null;
+         try
+         {
+            clazz = loader.loadClass(typeName);
+         }
+         catch (ClassNotFoundException e1)
+         {
+            // ignore
+         }
+         
+         if (clazz == null)
+         {
+            HashSet<Method> methods = new HashSet<>();
+            gatherMethods(type, methods);
+      
+            LambdaAssembler asm = new LambdaAssembler(typeName, methods);
+            byte[] code = asm.assembleClass();
+            
+            /*
+            // debug code
+            FileOutputStream fos;
+            try
+            {
+               int pos = typeName.lastIndexOf(".");
+               String fname = (pos >= 0 ? typeName.substring(pos + 1) : typeName);
+               fname = fname + ".class";
+               System.out.println("Lambda class file written to: " + fname);
+               fos = new FileOutputStream(fname);
+               fos.write(code);
+               fos.close();
+            }
+            catch (IOException exc)
+            {
+               exc.printStackTrace();
+            }
+            */
+            // load the proxy class with a custom class loader
+            try
+            {
+               clazz = loader.loadClass(typeName, code);
+            }
+            catch (ClassNotFoundException e)
+            {
+               throw new RuntimeException(e);
+            }
+         }
+         
+         try
+         {
+            Method mthd = clazz.getDeclaredMethod("getLambdas");
+            return (Map<Method, BiFunction<Object, Object[], Object>>) mthd.invoke(null);
+         }
+         catch (Throwable e)
+         {
+            throw new RuntimeException("Could not collect lambdas", e);
+         }
+      }
+   }
+
+   /**
+    * Gather all public, non-static methods from a type and all its super-classes/super-interfaces.
+    * 
+    * @param    type
+    *           The type.
+    * @param    methods
+    *           Set where all methods are gathered.
+    */
+   private void gatherMethods(Class<?> type, HashSet<Method> methods)
+   {
+      if (type == Object.class)
+      {
+         return;
+      }
+      
+      Method[] mthds = type.getDeclaredMethods();
+      for (int i = 0; i < mthds.length; i++)
+      {
+         Method m = mthds[i];
+         int mods = m.getModifiers();
+         if (!Modifier.isPublic(mods) || Modifier.isStatic(mods) || m.isSynthetic())
+         {
+            // only public, non-static methods are supported at this time
+            continue;
+         }
+         
+         if (methods.contains(m))
+         {
+            continue;
+         }
+         
+         methods.add(m);
+      }
+      
+      gatherMethods(type.getSuperclass(), methods);
+      
+      Class<?>[] ifaces = type.getInterfaces();
+      for (int i = 0; i < ifaces.length; i++)
+      {
+         gatherMethods(ifaces[i], methods);
+      }
+   }
+}

=== added file 'src/com/goldencode/proxy/LambdaHandlerPlugin.java'
--- old/src/com/goldencode/proxy/LambdaHandlerPlugin.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/LambdaHandlerPlugin.java	2022-12-20 10:53:10 +0000
@@ -0,0 +1,143 @@
+/*
+** Module   : LambdaHandlerPlugin.java
+** Abstract : 
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
+** 001 CA  20221212 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.lang.reflect.*;
+import java.util.function.*;
+
+import org.objectweb.asm.*;
+
+/**
+ * A plugin to assemble the function and consumer lambda instances as arguments for the 
+ * {@link LambdaInvocationHandler#invoke} method.
+ */
+public class LambdaHandlerPlugin 
+extends DefaultHandlerPlugin
+implements Opcodes
+{
+   /** Track the number of lambda expressions emitted in this proxy. */
+   private int lambdaNum = 0;
+   
+   /**
+    * Get the handler's class.
+    * 
+    * @return   {@link LambdaInvocationHandler} type.
+    */
+   @Override
+   public Class<? extends InvocationHandler> getHandlerClass()
+   {
+      return LambdaInvocationHandler.class;
+   }
+
+   /**
+    * Get the handler's invoke method signature.
+    */
+   @Override
+   public String getInvokeSignature()
+   {
+      return "(Ljava/lang/Object;" + 
+              "Ljava/lang/reflect/Method;" + 
+              "Ljava/util/function/BiFunction;" + 
+              "[Ljava/lang/Object;)Ljava/lang/Object;";
+   }
+   
+   /**
+    * Create the arguments related to invoking the target of this proxied call.  This will add, beside the 
+    * {@link Method} argument created by the {@link DefaultHandlerPlugin#createInvocationArgs}, a lambda
+    * expression as a {@link BiFunction} or {@link BiConsumer}, if the target method's return type is non-void
+    * or void, respectively.  If the target method is not public, it will emit 'null' arguments at these
+    * positions.
+    * 
+    * @param    classWriter
+    *           Class writer for proxy class.
+    * @param    mv
+    *           Method visitor for this method.
+    * @param    proxyName
+    *           Internal form of the proxy class' name.
+    * @param    method
+    *           Method for which this proxy is being implemented.
+    * @param    methodIndex
+    *           Index of this method within the array of methods used by the invocation handler.
+    */
+   @Override
+   public void createInvocationArgs(ClassWriter   classWriter, 
+                                    MethodVisitor mv, 
+                                    String        proxyName, 
+                                    Method        method, 
+                                    int           methodIndex)
+   {
+      super.createInvocationArgs(classWriter, mv, proxyName, method, methodIndex);
+      
+      if (!Modifier.isPublic(method.getModifiers()))
+      {
+         // only public methods can be emitted via lambda; everything else goes through reflection.
+         
+         mv.visitInsn(ACONST_NULL);
+         return;
+      }
+      
+      String lambdaName = "lambda$" + (lambdaNum++);
+      LambdaAssembler.emitLambdaMethod(classWriter, lambdaName, method);
+      LambdaAssembler.emitLambdaCall(proxyName, method, lambdaName, classWriter, mv);
+   }
+}

=== added file 'src/com/goldencode/proxy/LambdaInvocationHandler.java'
--- old/src/com/goldencode/proxy/LambdaInvocationHandler.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/proxy/LambdaInvocationHandler.java	2022-12-18 12:31:17 +0000
@@ -0,0 +1,121 @@
+/*
+** Module   : LambdaInvocationHandler.java
+** Abstract : 
+**
+** Copyright (c) 2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
+** 001 CA  20221212 Created initial version.
+*/
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.proxy;
+
+import java.lang.reflect.*;
+import java.util.function.*;
+
+/**
+ * A specialized handler which receives, beside the target {@link Method}, a {@link BiFunction} lambda  
+ * instance, to invoke a non-void or a void Java method, directly.
+ * <p>
+ * When both the function and consumer lambdas are null, it means the {@link Method} could not be invoked via
+ * a lambda expression (like a Java protected method).
+ */
+public interface LambdaInvocationHandler
+extends InvocationHandler
+{
+   /**
+    * The default invocation handler API.
+    *
+    * @param   proxy 
+    *          The target proxy object.
+    * @param   method 
+    *          The method to be executed.
+    * @param   args 
+    *          The method arguments.
+    *
+    * @return  The method invocation result.
+    *
+    * @throws  Throwable
+    */
+   @Override
+   public default Object invoke(Object proxy, Method method, Object[] args) 
+   throws Throwable
+   {
+      return invoke(proxy, method, null, args);
+   }
+   
+   /**
+    * An invoke handler which delegates the target call to either a function or consumer, if they are 
+    * generated in the proxy bytecode.
+    *
+    * @param   proxy 
+    *          The target proxy object.
+    * @param   method 
+    *          The method to be executed.
+    * @param   f
+    *          A function to invoke as target, when specified.
+    * @param   args 
+    *          The method arguments.
+    *
+    * @return  The method invocation result.
+    *
+    * @throws  Throwable
+    */
+   public Object invoke(Object proxy, 
+                        Method method, 
+                        BiFunction<Object, Object[], Object> f, 
+                        Object[] args) 
+   throws Throwable;
+}

=== modified file 'src/com/goldencode/proxy/ProxyAssembler.java'
--- old/src/com/goldencode/proxy/ProxyAssembler.java	2022-10-28 10:54:33 +0000
+++ new/src/com/goldencode/proxy/ProxyAssembler.java	2022-12-21 16:31:17 +0000
@@ -19,6 +19,8 @@
 **                  methods.
 ** 006 OM  20191123 Minor collection change.
 ** 007 TJD 20220504 Java 11 compatibility minor changes
+**     CA  20221212 Added support for a LambdaInvocationHandler which receives as arguments lambda expressions
+**                  to perform a direct call of the target, and avoid reflection.
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -214,6 +216,9 @@
    /** Object used to create class fields, methods, etc. */
    private final ClassWriter classWriter =
       new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+
+   /** A plugin to assemble the 'invoke' method for the proxy handler. */
+   private final InvocationHandlerPlugin handlerPlugin;
    
    /**
     * Constructor.
@@ -237,13 +242,17 @@
     *          interface, else <code>false</code>.  If <code>true</code>, no separate instance
     *          field will be assembled to store the invocation handler reference, as the instance
     *          of this class itself will act as the handler.
+    * @param   handlerPlugin
+    *          A plugin to assemble the 'invoke' method for the proxy handler.  If <code>null</code>, 
+    *          defaults to {@link DefaultHandlerPlugin}.
     */
    ProxyAssembler(String proxyName,
                   String parentName,
                   Class<?>[] interfaces,
                   Method[] methods,
                   ProxyAssemblerPlugin plugin,
-                  boolean parentIsHandler)
+                  boolean parentIsHandler,
+                  InvocationHandlerPlugin handlerPlugin)
    {
       if (plugin == null)
       {
@@ -266,6 +275,12 @@
       this.methods = methods;
       this.plugin = plugin;
       this.parentIsHandler = parentIsHandler;
+
+      if (handlerPlugin == null)
+      {
+         handlerPlugin = new DefaultHandlerPlugin();
+      }
+      this.handlerPlugin = handlerPlugin;
    }
    
    /**
@@ -302,8 +317,8 @@
       }
       
       // create the proxy class
-      classWriter.visit(V1_7,
-                        ACC_PUBLIC | ACC_FINAL,
+      classWriter.visit(V1_8,
+                        ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
                         proxyName,
                         null,
                         parentName,
@@ -321,7 +336,7 @@
          // add an instance member field for the InvocationHandler
          classWriter.visitField(ACC_PRIVATE | ACC_FINAL,
                                 "h",
-                                "Ljava/lang/reflect/InvocationHandler;",
+                                "L" + AsmUtils.commonToInternalTypeName(handlerPlugin.getHandlerClass()) + ";",
                                 null,
                                 null);
       }
@@ -357,7 +372,7 @@
                                     ProxyUtils.getCaughtExceptionTypeNames(method));
          
          mv.visitCode();
-         proxyMethod.assemble(classWriter, mv, method, i, parentIsHandler, proxyName);
+         proxyMethod.assemble(classWriter, mv, method, i, parentIsHandler, proxyName, handlerPlugin);
          mv.visitMaxs(0, 0);
          mv.visitEnd();
       }
@@ -467,7 +482,7 @@
       MethodVisitor mv =
          classWriter.visitMethod(ACC_PUBLIC,
                                  "<init>",
-                                 "(Ljava/lang/reflect/InvocationHandler;)V",
+                                 "(L" + AsmUtils.commonToInternalTypeName(handlerPlugin.getHandlerClass()) + ";)V",
                                  null,
                                  null);
       
@@ -487,7 +502,7 @@
       mv.visitFieldInsn(PUTFIELD,
                         proxyName,
                         "h",
-                        "Ljava/lang/reflect/InvocationHandler;");
+                        "L" + AsmUtils.commonToInternalTypeName(handlerPlugin.getHandlerClass()) + ";");
       
       // return from c'tor
       mv.visitInsn(RETURN);
@@ -563,6 +578,40 @@
                            boolean parentIsHandler,
                            String proxyName)
       {
+         assemble(classWriter, mv, method, methodIndex, parentIsHandler, proxyName, null);
+      }
+      
+      /**
+       * Assemble the bytecode which comprises the proxy method.
+       * 
+       * @param   classWriter
+       *          Class writer for proxy class.
+       * @param   mv
+       *          Method visitor for this method.
+       * @param   method
+       *          Method for which this proxy is being implemented.
+       * @param   methodIndex
+       *          Index of this method within the array of methods used by the invocation handler.
+       * @param   parentIsHandler
+       *          <code>true</code> if the parent class implements the
+       *          <code>InvocationHandler</code> interface, else <code>false</code>.  If
+       *          <code>true</code>, no separate instance field will be assembled to store the
+       *          invocation handler reference, as the instance of this class itself will act as
+       *          the handler.
+       * @param   proxyName
+       *          Internal form of the proxy class' name.
+       * @param   handlerPlugin
+       *          A plugin to assemble the 'invoke' method for the proxy handler.  If <code>null</code>, 
+       *          defaults to {@link DefaultHandlerPlugin}.
+       */
+      public void assemble(ClassWriter classWriter,
+                           MethodVisitor mv,
+                           Method method,
+                           int methodIndex,
+                           boolean parentIsHandler,
+                           String proxyName,
+                           InvocationHandlerPlugin handlerPlugin)
+      {
          // load invocation handler from field "h" or as "this" if the proxy
          // itself is the invocation handler
          mv.visitVarInsn(ALOAD, 0);
@@ -571,22 +620,14 @@
             mv.visitFieldInsn(GETFIELD,
                               proxyName,
                               "h",
-                              "Ljava/lang/reflect/InvocationHandler;");
+                              "L" + AsmUtils.commonToInternalTypeName(handlerPlugin.getHandlerClass()) + ";");
          }
          
          // load "this" object ref as the first parameter for later call to
          // InvocationHandler.invoke
          mv.visitVarInsn(ALOAD, 0);
          
-         // load target method from array of methods in static field "ma"
-         mv.visitFieldInsn(GETSTATIC,
-                           proxyName,
-                           "ma",
-                           "[Ljava/lang/reflect/Method;");
-         
-         // target method is at index "index" in the "ma" array
-         AsmUtils.pushInt(mv, methodIndex);
-         mv.visitInsn(AALOAD);
+         handlerPlugin.createInvocationArgs(classWriter, mv, proxyName, method, methodIndex);
          
          // create new array of Objects for method's arguments or push null
          // if there are no arguments
@@ -641,9 +682,9 @@
          
          // call InvocationHandler.invoke
          mv.visitMethodInsn(INVOKEINTERFACE,
-                            "java/lang/reflect/InvocationHandler",
+                            AsmUtils.commonToInternalTypeName(handlerPlugin.getHandlerClass()),
                             "invoke",
-                            "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
+                            handlerPlugin.getInvokeSignature(),
                             true);
          
          // determine method's return type

=== modified file 'src/com/goldencode/proxy/ProxyFactory.java'
--- old/src/com/goldencode/proxy/ProxyFactory.java	2022-10-28 10:54:33 +0000
+++ new/src/com/goldencode/proxy/ProxyFactory.java	2022-12-21 16:33:34 +0000
@@ -34,7 +34,6 @@
 **                  super-class hierarchy.
 ** 012 OM  20191123 Code format cleanup.
 ** 013 ECF 20200921 Compute CacheKey hashCode once and store it.
-**     TJD 20220504 Java 11 compatibility minor changes
 ** 014 CA  20220707 Save the 'doNotProxy' array hash codes - this array can be pretty large and the hash code
 **                  is expensive to compute.  Is the caller's responsibility to not send new instances of 
 **                  equal 'doNotProxy' array, as the cache is kept in an IdentityHashMap. 
@@ -42,6 +41,8 @@
 **                  is no need to use this instance.  Refs #6822
 **     CA  20221031 Javadoc fixes.
 **     TJD 20220504 Java 11 compatibility minor changes
+**     CA  20221212 Added support for a LambdaInvocationHandler which receives as arguments lambda expressions
+**                  to perform a direct call of the target, and avoid reflection.
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -557,13 +558,18 @@
                String proxyName = makeProxyClassName(parent, parentName);
                Method[] methods = gatherMethods(parent, proxyParent, interfaces, declaredOnly, doNotProxy);
                
+               InvocationHandlerPlugin handlerPlugin = handler instanceof LambdaInvocationHandler 
+                                                          ? new LambdaHandlerPlugin() 
+                                                          : new DefaultHandlerPlugin();
+               
                // assemble code for the proxy class
                ProxyAssembler asm = new ProxyAssembler(proxyName,
                                                        parentName,
                                                        interfaces,
                                                        methods,
                                                        (plugin == null ? null : plugin.get()),
-                                                       proxyIsHandler);
+                                                       proxyIsHandler,
+                                                       handlerPlugin);
                byte[] code = asm.assembleClass();
                
                /*
@@ -576,6 +582,9 @@
                                   ? proxyName.substring(pos + 1)
                                   : proxyName);
                   fname = fname + ".class";
+                  System.out.println(parent.toString());
+                  for (int i = 0; i < interfaces.length; i++)
+                     System.out.println(interfaces[i].toString());
                   System.out.println("Proxy class file written to: " + fname);
                   fos = new FileOutputStream(fname);
                   fos.write(code);
@@ -607,7 +616,7 @@
                
                if (!proxyIsHandler)
                {
-                  classCtors.put(clazz, clazz.getDeclaredConstructor(InvocationHandler.class));
+                  classCtors.put(clazz, clazz.getDeclaredConstructor(handlerPlugin.getHandlerClass()));
                }
             }
             

