This is an automated email from the ASF dual-hosted git repository.

lincoln pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git


The following commit(s) were added to refs/heads/master by this push:
     new 36302ed6e61 [FLINK-39273][table-common] Fix argument name conflict 
when UDF method contains lambda expression
36302ed6e61 is described below

commit 36302ed6e612e0f75136546f8026c16e72cea6ed
Author: dylanhz <[email protected]>
AuthorDate: Thu Mar 26 21:51:26 2026 +0800

    [FLINK-39273][table-common] Fix argument name conflict when UDF method 
contains lambda expression
    
    This closes #27787.
---
 .../table/types/extraction/ExtractionUtils.java    | 11 ++++++++++-
 .../types/extraction/ExtractionUtilsTest.java      | 23 ++++++++++++++++++++++
 .../extraction/TypeInferenceExtractorTest.java     | 18 +++++++++++++++++
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git 
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/extraction/ExtractionUtils.java
 
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/extraction/ExtractionUtils.java
index c788a71905e..4db958749ec 100644
--- 
a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/extraction/ExtractionUtils.java
+++ 
b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/extraction/ExtractionUtils.java
@@ -956,22 +956,31 @@ public final class ExtractionUtils {
      * <p>NOTE: the first parameter may be "this" if the function is not 
static. See more at <a
      * 
href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html";>3.6. 
Receiving
      * Arguments</a>
+     *
+     * <p>The visitor matches methods by both name and descriptor to avoid 
visiting synthetic
+     * methods generated by the compiler for lambda expressions (e.g. {@code 
lambda$eval$0}). These
+     * synthetic methods may share the same descriptor as the target method 
and would otherwise
+     * corrupt the extracted parameter names.
      */
     private static class ParameterExtractor extends ClassVisitor {
 
         private static final int OPCODE = Opcodes.ASM9;
 
+        private final String methodName;
+
         private final String methodDescriptor;
 
         private final Map<Integer, String> parameterNamesWithIndex = new 
TreeMap<>();
 
         ParameterExtractor(Constructor<?> constructor) {
             super(OPCODE);
+            methodName = "<init>";
             methodDescriptor = getConstructorDescriptor(constructor);
         }
 
         ParameterExtractor(Method method) {
             super(OPCODE);
+            methodName = method.getName();
             methodDescriptor = getMethodDescriptor(method);
         }
 
@@ -986,7 +995,7 @@ public final class ExtractionUtils {
         @Override
         public MethodVisitor visitMethod(
                 int access, String name, String descriptor, String signature, 
String[] exceptions) {
-            if (descriptor.equals(methodDescriptor)) {
+            if (name.equals(methodName) && 
descriptor.equals(methodDescriptor)) {
                 return new MethodVisitor(OPCODE) {
                     @Override
                     public void visitLocalVariable(
diff --git 
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/ExtractionUtilsTest.java
 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/ExtractionUtilsTest.java
index 431f0c23d91..5229729a7d2 100644
--- 
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/ExtractionUtilsTest.java
+++ 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/ExtractionUtilsTest.java
@@ -30,6 +30,7 @@ import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Supplier;
 
 import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
 
@@ -241,4 +242,26 @@ public class ExtractionUtilsTest {
                 List<CompletableFuture<Long>> listOfGenericFuture,
                 Long[] array) {}
     }
+
+    /**
+     * Verifies that {@link ExtractionUtils#extractExecutableNames} returns 
correct parameter names
+     * when a method contains a lambda that captures its own parameters, 
producing a synthetic
+     * method with the same bytecode descriptor.
+     */
+    @Test
+    void testExtractExecutableNamesWithLambdaCapture() {
+        Method method = 
ExtractionUtils.collectMethods(LambdaCaptureClass.class, "eval").get(0);
+        assertThat(ExtractionUtils.extractExecutableNames(method))
+                .isEqualTo(ImmutableList.of("id", "field"));
+    }
+
+    /** A single-method class where the lambda captures all parameters of the 
enclosing method. */
+    public static class LambdaCaptureClass {
+
+        @SuppressWarnings("unused")
+        public String eval(Long id, String field) {
+            Supplier<String> supplier = () -> String.valueOf(id) + field;
+            return supplier.get();
+        }
+    }
 }
diff --git 
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/TypeInferenceExtractorTest.java
 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/TypeInferenceExtractorTest.java
index 44dfb281133..f253819ce2c 100644
--- 
a/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/TypeInferenceExtractorTest.java
+++ 
b/flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/extraction/TypeInferenceExtractorTest.java
@@ -231,6 +231,17 @@ class TypeInferenceExtractorTest {
                                 TypeStrategies.explicit(
                                         
DataTypes.BIGINT().notNull().bridgedTo(long.class))),
                 // ---
+                // test eval method with lambda capture whose synthetic method 
shares the
+                // same bytecode descriptor, previously causing "Argument name 
conflict"
+                TestSpec.forScalarFunction(
+                                "ScalarFunctionWithLambdaCapture",
+                                ScalarFunctionWithLambdaCapture.class)
+                        .expectStaticArgument(
+                                StaticArgument.scalar("id", 
DataTypes.BIGINT(), false))
+                        .expectStaticArgument(
+                                StaticArgument.scalar("field", 
DataTypes.STRING(), false))
+                        
.expectOutput(TypeStrategies.explicit(DataTypes.STRING())),
+                // ---
                 // test overloaded arguments extraction async
                 TestSpec.forAsyncScalarFunction(OverloadedFunctionAsync.class)
                         .expectOutputMapping(
@@ -1590,6 +1601,13 @@ class TypeInferenceExtractorTest {
         }
     }
 
+    private static class ScalarFunctionWithLambdaCapture extends 
ScalarFunction {
+        public String eval(Long id, String field) {
+            Supplier<String> supplier = () -> String.valueOf(id) + field;
+            return supplier.get();
+        }
+    }
+
     private static class VarArgFunction extends ScalarFunction {
         public String eval(int i, int... more) {
             return null;

Reply via email to