Skip to content

Commit

Permalink
Replace more uses of ClassLoadingStrategy.Default.INJECTION (apache…
Browse files Browse the repository at this point in the history
…#23210)

* Replace more uses of `ClassLoadingStrategy.Default.INJECTION`

in preparation for Java 17+. Follow-up to:

apache@98f1f75.

* Move helper method to a shared ByteBuddyUtils class

* spotlessApply

* Apply suggestions from code review

Co-authored-by: Lukasz Cwik <lcwik@google.com>

* 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 <lcwik@google.com>

* Use ISE instead of LinkageError

* Add a missing import

* s/getClassLoader/findClassLoader

* fix Checker Framework error

---------

Co-authored-by: Lukasz Cwik <lcwik@google.com>
  • Loading branch information
cushon and lukecwik authored Feb 17, 2023
1 parent 8692026 commit 2b62912
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.beam.sdk.coders;

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

import java.io.IOException;
Expand All @@ -36,7 +37,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;
Expand All @@ -55,6 +55,7 @@
import org.apache.beam.sdk.schemas.Schema.Field;
import org.apache.beam.sdk.schemas.Schema.FieldType;
import org.apache.beam.sdk.schemas.SchemaCoder;
import org.apache.beam.sdk.util.common.ReflectHelpers;
import org.apache.beam.sdk.values.Row;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.Maps;
Expand Down Expand Up @@ -172,7 +173,9 @@ public static Coder<Row> generate(Schema schema) {
rowCoder =
builder
.make()
.load(Coder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.load(
ReflectHelpers.findClassLoader(schema.getClass().getClassLoader()),
getClassLoadingStrategy(schema.getClass()))
.getLoaded()
.getDeclaredConstructor(Coder[].class, int[].class)
.newInstance((Object) componentCoders, (Object) encodingPosToRowIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package org.apache.beam.sdk.schemas.utils;

import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
Expand All @@ -25,7 +27,6 @@
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodCall;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
Expand Down Expand Up @@ -99,7 +100,7 @@ private static <T> SchemaUserTypeCreator createCreator(Class<T> clazz, Schema sc
.make()
.load(
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(clazz))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.beam.sdk.schemas.utils;

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

import java.lang.reflect.Constructor;
Expand All @@ -43,7 +44,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.Implementation;
import net.bytebuddy.implementation.Implementation.Context;
Expand Down Expand Up @@ -459,7 +459,7 @@ public InstrumentedType prepare(InstrumentedType instrumentedType) {
.make()
.load(
ReflectHelpers.findClassLoader(((Class) fromType).getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy((Class) fromType))
.getLoaded();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package org.apache.beam.sdk.schemas.utils;

import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand All @@ -28,7 +30,6 @@
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.method.MethodDescription.ForLoadedMethod;
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;
Expand Down Expand Up @@ -162,7 +163,7 @@ public static <T> FieldValueGetter createGetter(
.load(
ReflectHelpers.findClassLoader(
typeInformation.getMethod().getDeclaringClass().getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(typeInformation.getMethod().getDeclaringClass()))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -226,7 +227,7 @@ public static FieldValueSetter createSetter(
.load(
ReflectHelpers.findClassLoader(
typeInformation.getMethod().getDeclaringClass().getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(typeInformation.getMethod().getDeclaringClass()))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -290,7 +291,7 @@ public static <T> SchemaUserTypeCreator createConstructorCreator(
.make()
.load(
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(clazz))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -338,7 +339,7 @@ public static <T> SchemaUserTypeCreator createStaticCreator(
.make()
.load(
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(clazz))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package org.apache.beam.sdk.schemas.utils;

import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -156,7 +158,7 @@ private static <T> SchemaUserTypeCreator createSetFieldCreator(
.make()
.load(
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(clazz))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -208,7 +210,7 @@ public static <T> SchemaUserTypeCreator createConstructorCreator(
.make()
.load(
ReflectHelpers.findClassLoader(clazz.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(clazz))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -299,7 +301,7 @@ public static <T> SchemaUserTypeCreator createStaticCreator(
.make()
.load(
ReflectHelpers.findClassLoader(field.getDeclaringClass().getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(field.getDeclaringClass()))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down Expand Up @@ -379,7 +381,7 @@ private static <ObjectT, ValueT> FieldValueSetter<ObjectT, ValueT> createSetter(
.make()
.load(
ReflectHelpers.findClassLoader(field.getDeclaringClass().getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
getClassLoadingStrategy(field.getDeclaringClass()))
.getLoaded()
.getDeclaredConstructor()
.newInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.beam.sdk.schemas.utils;

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

import com.google.auto.value.AutoValue;
Expand All @@ -36,7 +37,6 @@
import net.bytebuddy.description.type.TypeDescription.ForLoadedType;
import net.bytebuddy.description.type.TypeDescription.Generic;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.Implementation.Context;
Expand Down Expand Up @@ -66,6 +66,7 @@
import org.apache.beam.sdk.schemas.Schema.FieldType;
import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.IfNullElse;
import org.apache.beam.sdk.schemas.utils.ByteBuddyUtils.ShortCircuitReturnNull;
import org.apache.beam.sdk.util.common.ReflectHelpers;
import org.apache.beam.sdk.values.Row;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.collect.Lists;
Expand Down Expand Up @@ -177,7 +178,9 @@ static RowSelector createRowSelector(SchemaAndDescriptor schemaAndDescriptor) {
return builder
.visit(new AsmVisitorWrapper.ForDeclaredMethods().writerFlags(ClassWriter.COMPUTE_FRAMES))
.make()
.load(Row.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.load(
ReflectHelpers.findClassLoader(schemaAndDescriptor.getClass().getClassLoader()),
getClassLoadingStrategy(schemaAndDescriptor.getClass()))
.getLoaded()
.getDeclaredConstructor(Schema.class)
.newInstance(outputSchema);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.beam.sdk.transforms.reflect;

import static org.apache.beam.sdk.util.ByteBuddyUtils.getClassLoadingStrategy;
import static org.apache.beam.sdk.util.common.ReflectHelpers.findClassLoader;

import java.lang.reflect.Constructor;
Expand All @@ -27,7 +28,6 @@
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.Implementation;
Expand Down Expand Up @@ -225,9 +225,7 @@ public Constructor<?> load(final OnTimerMethodSpecifier onTimerMethodSpecifier)
Class<? extends OnTimerInvoker<?, ?>> res =
(Class<? extends OnTimerInvoker<?, ?>>)
unloaded
.load(
findClassLoader(fnClass.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
.load(findClassLoader(fnClass.getClassLoader()), getClassLoadingStrategy(fnClass))
.getLoaded();
return res;
}
Expand Down Expand Up @@ -277,9 +275,7 @@ public Constructor<?> load(final OnTimerMethodSpecifier onTimerMethodSpecifier)
Class<? extends OnTimerInvoker<?, ?>> res =
(Class<? extends OnTimerInvoker<?, ?>>)
unloaded
.load(
findClassLoader(fnClass.getClassLoader()),
ClassLoadingStrategy.Default.INJECTION)
.load(findClassLoader(fnClass.getClassLoader()), getClassLoadingStrategy(fnClass))
.getLoaded();
return res;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.beam.sdk.util;

import static java.util.Objects.requireNonNull;

import java.lang.reflect.Method;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import org.apache.beam.sdk.util.common.ReflectHelpers;

/** Utilities for working with Byte Buddy. */
public final class ByteBuddyUtils {
private ByteBuddyUtils() {} // Non-instantiable

/** Returns a class loading strategy that is compatible with Java 17+. */
public static ClassLoadingStrategy<ClassLoader> getClassLoadingStrategy(Class<?> targetClass) {
try {
ClassLoadingStrategy<ClassLoader> strategy;
if (ClassInjector.UsingLookup.isAvailable()) {
ClassLoader classLoader = ReflectHelpers.findClassLoader(targetClass);
Class<?> methodHandles = Class.forName("java.lang.invoke.MethodHandles", true, classLoader);
@SuppressWarnings("nullness") // MethodHandles#lookup accepts null
Object lookup = methodHandles.getMethod("lookup").invoke(null);
Class<?> lookupClass =
Class.forName("java.lang.invoke.MethodHandles$Lookup", true, classLoader);
Method privateLookupIn =
methodHandles.getMethod("privateLookupIn", Class.class, lookupClass);
@SuppressWarnings("nullness") // this is a static method, the receiver can be null
Object privateLookup = requireNonNull(privateLookupIn.invoke(null, targetClass, lookup));
strategy = ClassLoadingStrategy.UsingLookup.of(requireNonNull(privateLookup));
} else if (ClassInjector.UsingReflection.isAvailable()) {
strategy = ClassLoadingStrategy.Default.INJECTION;
} else {
throw new IllegalStateException("No code generation strategy available");
}
return strategy;
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("No code generation strategy available", e);
}
}
}

0 comments on commit 2b62912

Please sign in to comment.