From e0f1c7b95dd14787f5d5232adc9b2088c3d247a1 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 10 Jun 2026 22:58:00 +0200 Subject: [PATCH 1/5] Replace ClassLoadingStrategy with custom loading strategy --- .../beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java index 98f80f6786c8..00ab0b73b8c6 100644 --- a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java +++ b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java @@ -18,6 +18,7 @@ package org.apache.beam.sdk.extensions.protobuf; import static org.apache.beam.sdk.extensions.protobuf.ProtoSchemaTranslator.getFieldNumber; +import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -55,7 +56,6 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription.ForLoadedType; import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.dynamic.scaffold.InstrumentedType; import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.Implementation; @@ -546,7 +546,7 @@ public TypeConversion createSetterConversions(StackManipulati return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), ClassLoadingStrategy.Default.INJECTION) + .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(protoClass)) .getLoaded() .getDeclaredConstructor(List.class, OneOfType.class) .newInstance(getters, oneOfType); @@ -598,7 +598,7 @@ FieldValueSetter createOneOfSetter( return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), ClassLoadingStrategy.Default.INJECTION) + .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(protoBuilderClass)) .getLoaded() .getDeclaredConstructor(List.class) .newInstance(setters); @@ -1116,7 +1116,7 @@ static SchemaUserTypeCreator createB new AsmVisitorWrapper.ForDeclaredMethods() .writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), ClassLoadingStrategy.Default.INJECTION) + .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(builderClass)) .getLoaded() .getDeclaredConstructor() .newInstance(); From fed6eb206aa7dccf3ce7e9f5ff384b9e71e220a7 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 10 Jun 2026 23:09:18 +0200 Subject: [PATCH 2/5] Update findClassLoader calls to match --- .../beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java index 00ab0b73b8c6..a38da88fea14 100644 --- a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java +++ b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java @@ -546,7 +546,7 @@ public TypeConversion createSetterConversions(StackManipulati return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(protoClass)) + .load(ReflectHelpers.findClassLoader(protoClass), getClassLoadingStrategy(protoClass)) .getLoaded() .getDeclaredConstructor(List.class, OneOfType.class) .newInstance(getters, oneOfType); @@ -598,7 +598,7 @@ FieldValueSetter createOneOfSetter( return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(protoBuilderClass)) + .load(ReflectHelpers.findClassLoader(protoBuilderClass), getClassLoadingStrategy(protoBuilderClass)) .getLoaded() .getDeclaredConstructor(List.class) .newInstance(setters); @@ -1116,7 +1116,7 @@ static SchemaUserTypeCreator createB new AsmVisitorWrapper.ForDeclaredMethods() .writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(), getClassLoadingStrategy(builderClass)) + .load(ReflectHelpers.findClassLoader(builderClass), getClassLoadingStrategy(builderClass)) .getLoaded() .getDeclaredConstructor() .newInstance(); From 6e2e31f93fbe9c264133a4817e8fb59bd19d2a53 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 10 Jun 2026 23:58:20 +0200 Subject: [PATCH 3/5] spotless --- .../beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java index a38da88fea14..c912e83a0ccc 100644 --- a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java +++ b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java @@ -598,7 +598,9 @@ FieldValueSetter createOneOfSetter( return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(protoBuilderClass), getClassLoadingStrategy(protoBuilderClass)) + .load( + ReflectHelpers.findClassLoader(protoBuilderClass), + getClassLoadingStrategy(protoBuilderClass)) .getLoaded() .getDeclaredConstructor(List.class) .newInstance(setters); @@ -1116,7 +1118,9 @@ static SchemaUserTypeCreator createB new AsmVisitorWrapper.ForDeclaredMethods() .writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(builderClass), getClassLoadingStrategy(builderClass)) + .load( + ReflectHelpers.findClassLoader(builderClass), + getClassLoadingStrategy(builderClass)) .getLoaded() .getDeclaredConstructor() .newInstance(); From 08a6e3a80138ac32b02b199bb060ec5416935898 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 11 Jun 2026 13:43:31 +0200 Subject: [PATCH 4/5] Generate subclasses in beam's package and loade them in the same classloader as ProtoByteBuddyUtils --- .../protobuf/ProtoByteBuddyUtils.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java index c912e83a0ccc..7d26564d7b51 100644 --- a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java +++ b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java @@ -88,7 +88,6 @@ import org.apache.beam.sdk.schemas.SchemaUserTypeCreator; import org.apache.beam.sdk.schemas.logicaltypes.EnumerationType; import org.apache.beam.sdk.schemas.logicaltypes.OneOfType; -import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils; import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.ConvertType; import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.ConvertValueForGetter; import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.ConvertValueForSetter; @@ -99,7 +98,6 @@ import org.apache.beam.sdk.schemas.utils.JavaBeanUtils; import org.apache.beam.sdk.schemas.utils.ReflectUtils; import org.apache.beam.sdk.schemas.utils.ReflectUtils.ClassWithSchema; -import org.apache.beam.sdk.util.common.ReflectHelpers; import org.apache.beam.sdk.values.Row; import org.apache.beam.sdk.values.TypeDescriptor; import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.annotations.VisibleForTesting; @@ -511,8 +509,15 @@ public TypeConversion createSetterConversions(StackManipulati int[] keys = getterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray(); + @SuppressWarnings("unchecked") DynamicType.Builder> builder = - ByteBuddyUtils.subclassGetterInterface(BYTE_BUDDY, protoClass, OneOfType.Value.class); + (DynamicType.Builder) + BYTE_BUDDY + .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .subclass( + TypeDescription.Generic.Builder.parameterizedType( + FieldValueGetter.class, protoClass, OneOfType.Value.class) + .build()); builder = builder .method(ElementMatchers.named("name")) @@ -546,7 +551,9 @@ public TypeConversion createSetterConversions(StackManipulati return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load(ReflectHelpers.findClassLoader(protoClass), getClassLoadingStrategy(protoClass)) + .load( + ProtoByteBuddyUtils.class.getClassLoader(), + getClassLoadingStrategy(ProtoByteBuddyUtils.class)) .getLoaded() .getDeclaredConstructor(List.class, OneOfType.class) .newInstance(getters, oneOfType); @@ -568,9 +575,15 @@ FieldValueSetter createOneOfSetter( boolean contiguous = isContiguous(indices); int[] keys = setterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray(); + @SuppressWarnings("unchecked") DynamicType.Builder> builder = - ByteBuddyUtils.subclassSetterInterface( - BYTE_BUDDY, protoBuilderClass, OneOfType.Value.class); + (DynamicType.Builder) + BYTE_BUDDY + .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .subclass( + TypeDescription.Generic.Builder.parameterizedType( + FieldValueSetter.class, protoBuilderClass, OneOfType.Value.class) + .build()); builder = builder .method(ElementMatchers.named("name")) @@ -599,8 +612,8 @@ FieldValueSetter createOneOfSetter( .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() .load( - ReflectHelpers.findClassLoader(protoBuilderClass), - getClassLoadingStrategy(protoBuilderClass)) + ProtoByteBuddyUtils.class.getClassLoader(), + getClassLoadingStrategy(ProtoByteBuddyUtils.class)) .getLoaded() .getDeclaredConstructor(List.class) .newInstance(setters); @@ -1105,11 +1118,15 @@ static SchemaUserTypeCreator createB List> setters, Schema schema) { try { + @SuppressWarnings("unchecked") DynamicType.Builder> builder = (DynamicType.Builder) BYTE_BUDDY - .with(new InjectPackageStrategy(builderClass)) - .subclass(Supplier.class) + .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .subclass( + TypeDescription.Generic.Builder.parameterizedType( + Supplier.class, builderClass) + .build()) .method(ElementMatchers.named("get")) .intercept(new BuilderSupplier(protoClass)); Supplier supplier = @@ -1119,8 +1136,8 @@ static SchemaUserTypeCreator createB .writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() .load( - ReflectHelpers.findClassLoader(builderClass), - getClassLoadingStrategy(builderClass)) + ProtoByteBuddyUtils.class.getClassLoader(), + getClassLoadingStrategy(ProtoByteBuddyUtils.class)) .getLoaded() .getDeclaredConstructor() .newInstance(); From 154c9ad51980ba9580e122b4deb074ae995739f4 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 11 Jun 2026 13:54:50 +0200 Subject: [PATCH 5/5] Resolve classloader visibility issues in ProtoByteBuddyUtils --- .../protobuf/ProtoByteBuddyUtils.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java index 7d26564d7b51..a1e45868e87d 100644 --- a/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java +++ b/sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java @@ -98,6 +98,7 @@ import org.apache.beam.sdk.schemas.utils.JavaBeanUtils; import org.apache.beam.sdk.schemas.utils.ReflectUtils; import org.apache.beam.sdk.schemas.utils.ReflectUtils.ClassWithSchema; +import org.apache.beam.sdk.util.common.ReflectHelpers; import org.apache.beam.sdk.values.Row; import org.apache.beam.sdk.values.TypeDescriptor; import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.annotations.VisibleForTesting; @@ -509,11 +510,12 @@ public TypeConversion createSetterConversions(StackManipulati int[] keys = getterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray(); + Class targetClass = getLoadingTarget(protoClass); @SuppressWarnings("unchecked") DynamicType.Builder> builder = - (DynamicType.Builder) + (DynamicType.Builder>) BYTE_BUDDY - .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .with(new InjectPackageStrategy(targetClass)) .subclass( TypeDescription.Generic.Builder.parameterizedType( FieldValueGetter.class, protoClass, OneOfType.Value.class) @@ -551,9 +553,7 @@ public TypeConversion createSetterConversions(StackManipulati return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load( - ProtoByteBuddyUtils.class.getClassLoader(), - getClassLoadingStrategy(ProtoByteBuddyUtils.class)) + .load(targetClass.getClassLoader(), getClassLoadingStrategy(targetClass)) .getLoaded() .getDeclaredConstructor(List.class, OneOfType.class) .newInstance(getters, oneOfType); @@ -575,11 +575,12 @@ FieldValueSetter createOneOfSetter( boolean contiguous = isContiguous(indices); int[] keys = setterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray(); + Class targetClass = getLoadingTarget(protoBuilderClass); @SuppressWarnings("unchecked") DynamicType.Builder> builder = - (DynamicType.Builder) + (DynamicType.Builder>) BYTE_BUDDY - .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .with(new InjectPackageStrategy(targetClass)) .subclass( TypeDescription.Generic.Builder.parameterizedType( FieldValueSetter.class, protoBuilderClass, OneOfType.Value.class) @@ -611,9 +612,7 @@ FieldValueSetter createOneOfSetter( return builder .visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load( - ProtoByteBuddyUtils.class.getClassLoader(), - getClassLoadingStrategy(ProtoByteBuddyUtils.class)) + .load(targetClass.getClassLoader(), getClassLoadingStrategy(targetClass)) .getLoaded() .getDeclaredConstructor(List.class) .newInstance(setters); @@ -1118,11 +1117,12 @@ static SchemaUserTypeCreator createB List> setters, Schema schema) { try { + Class targetClass = getLoadingTarget(builderClass); @SuppressWarnings("unchecked") DynamicType.Builder> builder = - (DynamicType.Builder) + (DynamicType.Builder>) BYTE_BUDDY - .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class)) + .with(new InjectPackageStrategy(targetClass)) .subclass( TypeDescription.Generic.Builder.parameterizedType( Supplier.class, builderClass) @@ -1135,9 +1135,7 @@ static SchemaUserTypeCreator createB new AsmVisitorWrapper.ForDeclaredMethods() .writerFlags(ClassWriter.COMPUTE_FRAMES)) .make() - .load( - ProtoByteBuddyUtils.class.getClassLoader(), - getClassLoadingStrategy(ProtoByteBuddyUtils.class)) + .load(targetClass.getClassLoader(), getClassLoadingStrategy(targetClass)) .getLoaded() .getDeclaredConstructor() .newInstance(); @@ -1211,4 +1209,12 @@ public ByteCodeAppender appender(final Target implementationTarget) { }; } } + + private static Class getLoadingTarget(Class protoClass) { + ClassLoader loader = ReflectHelpers.findClassLoader(ProtoByteBuddyUtils.class, protoClass); + if (loader == ProtoByteBuddyUtils.class.getClassLoader()) { + return ProtoByteBuddyUtils.class; + } + return protoClass; + } }