gemini-code-assist[bot] commented on code in PR #38906:
URL: https://github.com/apache/beam/pull/38906#discussion_r3395554940


##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -546,7 +551,9 @@ public TypeConversion<StackManipulation> 
createSetterConversions(StackManipulati
       return builder
           .visit(new 
AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES))
           .make()
-          .load(ReflectHelpers.findClassLoader(), 
ClassLoadingStrategy.Default.INJECTION)
+          .load(
+              ProtoByteBuddyUtils.class.getClassLoader(),
+              getClassLoadingStrategy(ProtoByteBuddyUtils.class))

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Using `ProtoByteBuddyUtils.class.getClassLoader()` and 
`getClassLoadingStrategy(ProtoByteBuddyUtils.class)` can introduce classloader 
visibility issues in multi-classloader environments (such as Spark, Flink, or 
application servers).
   
   ### The Issue
   In these environments, the Beam SDK libraries (including 
`ProtoByteBuddyUtils`) are often loaded by a parent/system classloader, while 
the user's pipeline code and generated protocol buffer classes (e.g., 
`protoClass`) are loaded by a child/user classloader.
   
   By forcing the generated ByteBuddy classes to be loaded into 
`ProtoByteBuddyUtils.class.getClassLoader()` (the parent classloader), the 
generated classes will not be able to resolve or access the user's proto 
classes (which reside in the child classloader). This will result in a 
`NoClassDefFoundError` or `ClassNotFoundException` at runtime when the 
generated getter/setter/creator is invoked.
   
   ### Suggested Approach
   To ensure the generated classes can see the user's proto classes, they 
should be loaded using the user class's classloader (e.g., 
`protoClass.getClassLoader()`) and a strategy appropriate for that classloader 
(e.g., `getClassLoadingStrategy(protoClass)`).
   
   However, if we use `getClassLoadingStrategy(protoClass)`, we must also 
ensure that the package injection strategy (`InjectPackageStrategy`) targets 
`protoClass`'s package, because lookup-based class loading strategies 
(`MethodHandles.privateLookupIn`) require the generated class to be in the same 
package as the lookup target.
   
   Please consider if we can use `protoClass` (or `builderClass`) as the target 
for both the package injection and the classloading strategy, similar to how it 
is handled in other parts of Beam's schema utilities, or if there is an 
alternative way to preserve classloader delegation.



##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -598,7 +611,9 @@ FieldValueSetter<ProtoBuilderT, Object> createOneOfSetter(
       return builder
           .visit(new 
AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES))
           .make()
-          .load(ReflectHelpers.findClassLoader(), 
ClassLoadingStrategy.Default.INJECTION)
+          .load(
+              ProtoByteBuddyUtils.class.getClassLoader(),
+              getClassLoadingStrategy(ProtoByteBuddyUtils.class))

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Similar to the issue described in `createOneOfGetter`, using 
`ProtoByteBuddyUtils.class.getClassLoader()` here can cause 
`NoClassDefFoundError` in multi-classloader environments where the user's proto 
classes are loaded by a child classloader.



##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -511,8 +509,15 @@ public TypeConversion<StackManipulation> 
createSetterConversions(StackManipulati
 
     int[] keys = 
getterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray();
 
+    @SuppressWarnings("unchecked")
     DynamicType.Builder<FieldValueGetter<@NonNull ProtoT, OneOfType.Value>> 
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());

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Instead of casting to the raw type `(DynamicType.Builder)`, we can cast 
directly to the parameterized type 
`(DynamicType.Builder<FieldValueGetter<@NonNull ProtoT, OneOfType.Value>>)` to 
avoid raw type usage and make the cast more explicit.
   
   ```suggestion
       @SuppressWarnings("unchecked")
       DynamicType.Builder<FieldValueGetter<@NonNull ProtoT, OneOfType.Value>> 
builder =
           (DynamicType.Builder<FieldValueGetter<@NonNull ProtoT, 
OneOfType.Value>>)
               BYTE_BUDDY
                   .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class))
                   .subclass(
                       TypeDescription.Generic.Builder.parameterizedType(
                               FieldValueGetter.class, protoClass, 
OneOfType.Value.class)
                           .build());
   ```



##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -568,9 +575,15 @@ FieldValueSetter<ProtoBuilderT, Object> createOneOfSetter(
     boolean contiguous = isContiguous(indices);
     int[] keys = 
setterMethodMap.keySet().stream().mapToInt(Integer::intValue).toArray();
 
+    @SuppressWarnings("unchecked")
     DynamicType.Builder<FieldValueSetter<ProtoBuilderT, Object>> 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());

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Instead of casting to the raw type `(DynamicType.Builder)`, we can cast 
directly to the parameterized type 
`(DynamicType.Builder<FieldValueSetter<ProtoBuilderT, Object>>)` to avoid raw 
type usage.
   
   ```suggestion
       @SuppressWarnings("unchecked")
       DynamicType.Builder<FieldValueSetter<ProtoBuilderT, Object>> builder =
           (DynamicType.Builder<FieldValueSetter<ProtoBuilderT, Object>>)
               BYTE_BUDDY
                   .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class))
                   .subclass(
                       TypeDescription.Generic.Builder.parameterizedType(
                               FieldValueSetter.class, protoBuilderClass, 
OneOfType.Value.class)
                           .build());
   ```



##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -1103,11 +1118,15 @@ static <ProtoBuilderT extends MessageLite.Builder> 
SchemaUserTypeCreator createB
       List<FieldValueSetter<ProtoBuilderT, Object>> setters,
       Schema schema) {
     try {
+      @SuppressWarnings("unchecked")
       DynamicType.Builder<Supplier<ProtoBuilderT>> 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())

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Instead of casting to the raw type `(DynamicType.Builder)`, we can cast 
directly to the parameterized type 
`(DynamicType.Builder<Supplier<ProtoBuilderT>>)` to avoid raw type usage.
   
   ```suggestion
         @SuppressWarnings("unchecked")
         DynamicType.Builder<Supplier<ProtoBuilderT>> builder =
             (DynamicType.Builder<Supplier<ProtoBuilderT>>)
                 BYTE_BUDDY
                     .with(new InjectPackageStrategy(ProtoByteBuddyUtils.class))
                     .subclass(
                         TypeDescription.Generic.Builder.parameterizedType(
                                 Supplier.class, builderClass)
                             .build())
   ```



##########
sdks/java/extensions/protobuf/src/main/java/org/apache/beam/sdk/extensions/protobuf/ProtoByteBuddyUtils.java:
##########
@@ -1116,7 +1135,9 @@ static <ProtoBuilderT extends MessageLite.Builder> 
SchemaUserTypeCreator createB
                   new AsmVisitorWrapper.ForDeclaredMethods()
                       .writerFlags(ClassWriter.COMPUTE_FRAMES))
               .make()
-              .load(ReflectHelpers.findClassLoader(), 
ClassLoadingStrategy.Default.INJECTION)
+              .load(
+                  ProtoByteBuddyUtils.class.getClassLoader(),
+                  getClassLoadingStrategy(ProtoByteBuddyUtils.class))

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Similar to the issue described in `createOneOfGetter`, using 
`ProtoByteBuddyUtils.class.getClassLoader()` here can cause 
`NoClassDefFoundError` in multi-classloader environments where the user's proto 
classes are loaded by a child classloader.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to