/*
* Copyright 2014 - 2020 Rafael Winterhalter
*
* Licensed 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 net.bytebuddy.implementation.auxiliary;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.MethodAccessorFactory;
import net.bytebuddy.implementation.MethodCall;
import net.bytebuddy.utility.CompoundList;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
A PrivilegedExceptionAction
to lookup a method constant using an AccessController
. /**
* A {@link PrivilegedExceptionAction} to lookup a method constant using an {@link java.security.AccessController}.
*/
public enum PrivilegedMemberLookupAction implements AuxiliaryType {
Looks up a method using Class.getDeclaredMethod(String, Class[])
. /**
* Looks up a method using {@link Class#getDeclaredMethod(String, Class[])}.
*/
FOR_PUBLIC_METHOD("getMethod", "name", String.class, "parameters", Class[].class),
Looks up a method using Class.getDeclaredMethod(String, Class[])
. /**
* Looks up a method using {@link Class#getDeclaredMethod(String, Class[])}.
*/
FOR_DECLARED_METHOD("getDeclaredMethod", "name", String.class, "parameters", Class[].class),
Looks up a method using Class.getConstructor(Class[])
. /**
* Looks up a method using {@link Class#getConstructor(Class[])}.
*/
FOR_PUBLIC_CONSTRUCTOR("getConstructor", "parameters", Class[].class),
Looks up a method using Class.getDeclaredConstructor(Class[])
. /**
* Looks up a method using {@link Class#getDeclaredConstructor(Class[])}.
*/
FOR_DECLARED_CONSTRUCTOR("getDeclaredConstructor", "parameters", Class[].class);
The name of the field that holds the type instance to look the method up from.
/**
* The name of the field that holds the type instance to look the method up from.
*/
private static final String TYPE_FIELD = "type";
The default constructor of the Object
class. /**
* The default constructor of the {@link Object} class.
*/
private static final MethodDescription.InDefinedShape DEFAULT_CONSTRUCTOR = TypeDescription.OBJECT.getDeclaredMethods()
.filter(isConstructor())
.getOnly();
The method to invoke from the action.
/**
* The method to invoke from the action.
*/
private final MethodDescription.InDefinedShape methodDescription;
A mapping of field names to their types in a fixed iteration order.
/**
* A mapping of field names to their types in a fixed iteration order.
*/
private final Map<String, Class<?>> fields;
Creates a privileged method constant action with one argument.
Params: - name – The name of the method.
- field – The name of a field to define.
- type – The type of the field to define.
/**
* Creates a privileged method constant action with one argument.
*
* @param name The name of the method.
* @param field The name of a field to define.
* @param type The type of the field to define.
*/
PrivilegedMemberLookupAction(String name, String field, Class<?> type) {
try {
methodDescription = new MethodDescription.ForLoadedMethod(Class.class.getMethod(name, type));
} catch (NoSuchMethodException exception) {
throw new IllegalStateException("Could not locate method: " + name, exception);
}
fields = Collections.<String, Class<?>>singletonMap(field, type);
}
Creates a privileged method constant action with one argument.
Params: - name – The name of the method.
- firstField – The name of the first field to define.
- firstType – The type of the first field to define.
- secondField – The name of the second field to define.
- secondType – The type of the second field to define.
/**
* Creates a privileged method constant action with one argument.
*
* @param name The name of the method.
* @param firstField The name of the first field to define.
* @param firstType The type of the first field to define.
* @param secondField The name of the second field to define.
* @param secondType The type of the second field to define.
*/
PrivilegedMemberLookupAction(String name, String firstField, Class<?> firstType, String secondField, Class<?> secondType) {
try {
methodDescription = new MethodDescription.ForLoadedMethod(Class.class.getMethod(name, firstType, secondType));
} catch (NoSuchMethodException exception) {
throw new IllegalStateException("Could not locate method: " + name, exception);
}
fields = new LinkedHashMap<String, Class<?>>();
fields.put(firstField, firstType);
fields.put(secondField, secondType);
}
Returns an auxiliary type for loading the supplied method description as a constant.
Params: - methodDescription – The method description to represent as a constant.
Returns: An appropriate auxiliary type.
/**
* Returns an auxiliary type for loading the supplied method description as a constant.
*
* @param methodDescription The method description to represent as a constant.
* @return An appropriate auxiliary type.
*/
public static AuxiliaryType of(MethodDescription methodDescription) {
if (methodDescription.isConstructor()) {
return methodDescription.isPublic()
? FOR_PUBLIC_CONSTRUCTOR
: FOR_DECLARED_CONSTRUCTOR;
} else if (methodDescription.isMethod()) {
return methodDescription.isPublic()
? FOR_PUBLIC_METHOD
: FOR_DECLARED_METHOD;
} else {
throw new IllegalStateException("Cannot load constant for type initializer: " + methodDescription);
}
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
public DynamicType make(String auxiliaryTypeName,
ClassFileVersion classFileVersion,
MethodAccessorFactory methodAccessorFactory) {
Implementation.Composable constructor = MethodCall.invoke(DEFAULT_CONSTRUCTOR).andThen(FieldAccessor.ofField(TYPE_FIELD).setsArgumentAt(0));
int index = 1;
for (String field : fields.keySet()) {
constructor = constructor.andThen(FieldAccessor.ofField(field).setsArgumentAt(index++));
}
DynamicType.Builder<?> builder = new ByteBuddy(classFileVersion)
.with(TypeValidation.DISABLED)
.subclass(PrivilegedExceptionAction.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.name(auxiliaryTypeName)
.modifiers(DEFAULT_TYPE_MODIFIER)
.defineConstructor(Visibility.PUBLIC)
.withParameters(CompoundList.of(Class.class, new ArrayList<Class<?>>(fields.values())))
.intercept(constructor)
.method(named("run"))
.intercept(MethodCall.invoke(methodDescription)
.onField(TYPE_FIELD)
.withField(fields.keySet().toArray(new String[0])))
.defineField(TYPE_FIELD, Class.class, Visibility.PRIVATE);
for (Map.Entry<String, Class<?>> entry : fields.entrySet()) {
builder = builder.defineField(entry.getKey(), entry.getValue(), Visibility.PRIVATE);
}
return builder.make();
}
}