Skip to content

Commit 2b62912

Browse files
cushonlukecwik
andauthored
Replace more uses of ClassLoadingStrategy.Default.INJECTION (#23210)
* Replace more uses of `ClassLoadingStrategy.Default.INJECTION` in preparation for Java 17+. Follow-up to: 98f1f75. * Move helper method to a shared ByteBuddyUtils class * spotlessApply * Apply suggestions from code review Co-authored-by: Lukasz Cwik <[email protected]> * Fix nullness issues, add an overload that takes a custom classloader * spotless apply * Fix imports * Update sdks/java/core/src/main/java/org/apache/beam/sdk/util/ByteBuddyUtils.java Co-authored-by: Lukasz Cwik <[email protected]> * Use ISE instead of LinkageError * Add a missing import * s/getClassLoader/findClassLoader * fix Checker Framework error --------- Co-authored-by: Lukasz Cwik <[email protected]>
1 parent 8692026 commit 2b62912

File tree

8 files changed

+87
-24
lines changed

8 files changed

+87
-24
lines changed

sdks/java/core/src/main/java/org/apache/beam/sdk/coders/RowCoderGenerator.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.beam.sdk.coders;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
2021
import static org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkState;
2122

2223
import java.io.IOException;
@@ -36,7 +37,6 @@
3637
import net.bytebuddy.description.type.TypeDescription;
3738
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
3839
import net.bytebuddy.dynamic.DynamicType;
39-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
4040
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
4141
import net.bytebuddy.implementation.FixedValue;
4242
import net.bytebuddy.implementation.Implementation;
@@ -55,6 +55,7 @@
5555
import org.apache.beam.sdk.schemas.Schema.Field;
5656
import org.apache.beam.sdk.schemas.Schema.FieldType;
5757
import org.apache.beam.sdk.schemas.SchemaCoder;
58+
import org.apache.beam.sdk.util.common.ReflectHelpers;
5859
import org.apache.beam.sdk.values.Row;
5960
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions;
6061
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.Maps;
@@ -172,7 +173,9 @@ public static Coder<Row> generate(Schema schema) {
172173
rowCoder =
173174
builder
174175
.make()
175-
.load(Coder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
176+
.load(
177+
ReflectHelpers.findClassLoader(schema.getClass().getClassLoader()),
178+
getClassLoadingStrategy(schema.getClass()))
176179
.getLoaded()
177180
.getDeclaredConstructor(Coder[].class, int[].class)
178181
.newInstance((Object) componentCoders, (Object) encodingPosToRowIndex);

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/AvroByteBuddyUtils.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package org.apache.beam.sdk.schemas.utils;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
21+
2022
import java.lang.reflect.Constructor;
2123
import java.lang.reflect.InvocationTargetException;
2224
import java.lang.reflect.Type;
@@ -25,7 +27,6 @@
2527
import net.bytebuddy.asm.AsmVisitorWrapper;
2628
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
2729
import net.bytebuddy.dynamic.DynamicType;
28-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
2930
import net.bytebuddy.implementation.MethodCall;
3031
import net.bytebuddy.implementation.bytecode.StackManipulation;
3132
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
@@ -99,7 +100,7 @@ private static <T> SchemaUserTypeCreator createCreator(Class<T> clazz, Schema sc
99100
.make()
100101
.load(
101102
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
102-
ClassLoadingStrategy.Default.INJECTION)
103+
getClassLoadingStrategy(clazz))
103104
.getLoaded()
104105
.getDeclaredConstructor()
105106
.newInstance();

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/ByteBuddyUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.beam.sdk.schemas.utils;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
2021
import static org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkNotNull;
2122

2223
import java.lang.reflect.Constructor;
@@ -43,7 +44,6 @@
4344
import net.bytebuddy.description.type.TypeDescription;
4445
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
4546
import net.bytebuddy.dynamic.DynamicType;
46-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
4747
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
4848
import net.bytebuddy.implementation.Implementation;
4949
import net.bytebuddy.implementation.Implementation.Context;
@@ -459,7 +459,7 @@ public InstrumentedType prepare(InstrumentedType instrumentedType) {
459459
.make()
460460
.load(
461461
ReflectHelpers.findClassLoader(((Class) fromType).getClassLoader()),
462-
ClassLoadingStrategy.Default.INJECTION)
462+
getClassLoadingStrategy((Class) fromType))
463463
.getLoaded();
464464
}
465465

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/JavaBeanUtils.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package org.apache.beam.sdk.schemas.utils;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
21+
2022
import java.lang.reflect.Constructor;
2123
import java.lang.reflect.InvocationTargetException;
2224
import java.lang.reflect.Method;
@@ -28,7 +30,6 @@
2830
import net.bytebuddy.asm.AsmVisitorWrapper;
2931
import net.bytebuddy.description.method.MethodDescription.ForLoadedMethod;
3032
import net.bytebuddy.dynamic.DynamicType;
31-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
3233
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
3334
import net.bytebuddy.implementation.FixedValue;
3435
import net.bytebuddy.implementation.Implementation;
@@ -162,7 +163,7 @@ public static <T> FieldValueGetter createGetter(
162163
.load(
163164
ReflectHelpers.findClassLoader(
164165
typeInformation.getMethod().getDeclaringClass().getClassLoader()),
165-
ClassLoadingStrategy.Default.INJECTION)
166+
getClassLoadingStrategy(typeInformation.getMethod().getDeclaringClass()))
166167
.getLoaded()
167168
.getDeclaredConstructor()
168169
.newInstance();
@@ -226,7 +227,7 @@ public static FieldValueSetter createSetter(
226227
.load(
227228
ReflectHelpers.findClassLoader(
228229
typeInformation.getMethod().getDeclaringClass().getClassLoader()),
229-
ClassLoadingStrategy.Default.INJECTION)
230+
getClassLoadingStrategy(typeInformation.getMethod().getDeclaringClass()))
230231
.getLoaded()
231232
.getDeclaredConstructor()
232233
.newInstance();
@@ -290,7 +291,7 @@ public static <T> SchemaUserTypeCreator createConstructorCreator(
290291
.make()
291292
.load(
292293
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
293-
ClassLoadingStrategy.Default.INJECTION)
294+
getClassLoadingStrategy(clazz))
294295
.getLoaded()
295296
.getDeclaredConstructor()
296297
.newInstance();
@@ -338,7 +339,7 @@ public static <T> SchemaUserTypeCreator createStaticCreator(
338339
.make()
339340
.load(
340341
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
341-
ClassLoadingStrategy.Default.INJECTION)
342+
getClassLoadingStrategy(clazz))
342343
.getLoaded()
343344
.getDeclaredConstructor()
344345
.newInstance();

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/POJOUtils.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package org.apache.beam.sdk.schemas.utils;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
21+
2022
import java.lang.reflect.Constructor;
2123
import java.lang.reflect.Field;
2224
import java.lang.reflect.InvocationTargetException;
@@ -156,7 +158,7 @@ private static <T> SchemaUserTypeCreator createSetFieldCreator(
156158
.make()
157159
.load(
158160
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
159-
ClassLoadingStrategy.Default.INJECTION)
161+
getClassLoadingStrategy(clazz))
160162
.getLoaded()
161163
.getDeclaredConstructor()
162164
.newInstance();
@@ -208,7 +210,7 @@ public static <T> SchemaUserTypeCreator createConstructorCreator(
208210
.make()
209211
.load(
210212
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
211-
ClassLoadingStrategy.Default.INJECTION)
213+
getClassLoadingStrategy(clazz))
212214
.getLoaded()
213215
.getDeclaredConstructor()
214216
.newInstance();
@@ -299,7 +301,7 @@ public static <T> SchemaUserTypeCreator createStaticCreator(
299301
.make()
300302
.load(
301303
ReflectHelpers.findClassLoader(field.getDeclaringClass().getClassLoader()),
302-
ClassLoadingStrategy.Default.INJECTION)
304+
getClassLoadingStrategy(field.getDeclaringClass()))
303305
.getLoaded()
304306
.getDeclaredConstructor()
305307
.newInstance();
@@ -379,7 +381,7 @@ private static <ObjectT, ValueT> FieldValueSetter<ObjectT, ValueT> createSetter(
379381
.make()
380382
.load(
381383
ReflectHelpers.findClassLoader(field.getDeclaringClass().getClassLoader()),
382-
ClassLoadingStrategy.Default.INJECTION)
384+
getClassLoadingStrategy(field.getDeclaringClass()))
383385
.getLoaded()
384386
.getDeclaredConstructor()
385387
.newInstance();

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/SelectByteBuddyHelpers.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.beam.sdk.schemas.utils;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
2021
import static org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkNotNull;
2122

2223
import com.google.auto.value.AutoValue;
@@ -36,7 +37,6 @@
3637
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
3738
import net.bytebuddy.description.type.TypeDescription.Generic;
3839
import net.bytebuddy.dynamic.DynamicType;
39-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
4040
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
4141
import net.bytebuddy.implementation.Implementation;
4242
import net.bytebuddy.implementation.Implementation.Context;
@@ -66,6 +66,7 @@
6666
import org.apache.beam.sdk.schemas.Schema.FieldType;
6767
import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.IfNullElse;
6868
import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.ShortCircuitReturnNull;
69+
import org.apache.beam.sdk.util.common.ReflectHelpers;
6970
import org.apache.beam.sdk.values.Row;
7071
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions;
7172
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.Lists;
@@ -177,7 +178,9 @@ static RowSelector createRowSelector(SchemaAndDescriptor schemaAndDescriptor) {
177178
return builder
178179
.visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES))
179180
.make()
180-
.load(Row.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
181+
.load(
182+
ReflectHelpers.findClassLoader(schemaAndDescriptor.getClass().getClassLoader()),
183+
getClassLoadingStrategy(schemaAndDescriptor.getClass()))
181184
.getLoaded()
182185
.getDeclaredConstructor(Schema.class)
183186
.newInstance(outputSchema);

sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/ByteBuddyOnTimerInvokerFactory.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.beam.sdk.transforms.reflect;
1919

20+
import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
2021
import static org.apache.beam.sdk.util.common.ReflectHelpers.findClassLoader;
2122

2223
import java.lang.reflect.Constructor;
@@ -27,7 +28,6 @@
2728
import net.bytebuddy.description.modifier.Visibility;
2829
import net.bytebuddy.description.type.TypeDescription;
2930
import net.bytebuddy.dynamic.DynamicType;
30-
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
3131
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
3232
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
3333
import net.bytebuddy.implementation.Implementation;
@@ -225,9 +225,7 @@ public Constructor<?> load(final OnTimerMethodSpecifier onTimerMethodSpecifier)
225225
Class<? extends OnTimerInvoker<?, ?>> res =
226226
(Class<? extends OnTimerInvoker<?, ?>>)
227227
unloaded
228-
.load(
229-
findClassLoader(fnClass.getClassLoader()),
230-
ClassLoadingStrategy.Default.INJECTION)
228+
.load(findClassLoader(fnClass.getClassLoader()), getClassLoadingStrategy(fnClass))
231229
.getLoaded();
232230
return res;
233231
}
@@ -277,9 +275,7 @@ public Constructor<?> load(final OnTimerMethodSpecifier onTimerMethodSpecifier)
277275
Class<? extends OnTimerInvoker<?, ?>> res =
278276
(Class<? extends OnTimerInvoker<?, ?>>)
279277
unloaded
280-
.load(
281-
findClassLoader(fnClass.getClassLoader()),
282-
ClassLoadingStrategy.Default.INJECTION)
278+
.load(findClassLoader(fnClass.getClassLoader()), getClassLoadingStrategy(fnClass))
283279
.getLoaded();
284280
return res;
285281
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.beam.sdk.util;
19+
20+
import static java.util.Objects.requireNonNull;
21+
22+
import java.lang.reflect.Method;
23+
import net.bytebuddy.dynamic.loading.ClassInjector;
24+
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
25+
import org.apache.beam.sdk.util.common.ReflectHelpers;
26+
27+
/** Utilities for working with Byte Buddy. */
28+
public final class ByteBuddyUtils {
29+
private ByteBuddyUtils() {} // Non-instantiable
30+
31+
/** Returns a class loading strategy that is compatible with Java 17+. */
32+
public static ClassLoadingStrategy<ClassLoader> getClassLoadingStrategy(Class<?> targetClass) {
33+
try {
34+
ClassLoadingStrategy<ClassLoader> strategy;
35+
if (ClassInjector.UsingLookup.isAvailable()) {
36+
ClassLoader classLoader = ReflectHelpers.findClassLoader(targetClass);
37+
Class<?> methodHandles = Class.forName("java.lang.invoke.MethodHandles", true, classLoader);
38+
@SuppressWarnings("nullness") // MethodHandles#lookup accepts null
39+
Object lookup = methodHandles.getMethod("lookup").invoke(null);
40+
Class<?> lookupClass =
41+
Class.forName("java.lang.invoke.MethodHandles$Lookup", true, classLoader);
42+
Method privateLookupIn =
43+
methodHandles.getMethod("privateLookupIn", Class.class, lookupClass);
44+
@SuppressWarnings("nullness") // this is a static method, the receiver can be null
45+
Object privateLookup = requireNonNull(privateLookupIn.invoke(null, targetClass, lookup));
46+
strategy = ClassLoadingStrategy.UsingLookup.of(requireNonNull(privateLookup));
47+
} else if (ClassInjector.UsingReflection.isAvailable()) {
48+
strategy = ClassLoadingStrategy.Default.INJECTION;
49+
} else {
50+
throw new IllegalStateException("No code generation strategy available");
51+
}
52+
return strategy;
53+
} catch (ReflectiveOperationException e) {
54+
throw new IllegalStateException("No code generation strategy available", e);
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)