/*
* Copyright 2017-2020 original authors
*
* 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
*
* https://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 io.micronaut.inject.writer;
import edu.umd.cs.findbugs.annotations.Nullable;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Generated;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.reflect.ClassUtils;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ArrayUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.inject.annotation.AnnotationMetadataWriter;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import io.micronaut.inject.ast.*;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Supplier;
Abstract class that writes generated classes to disk and provides convenience methods for building classes.
Author: Graeme Rocher Since: 1.0
/**
* Abstract class that writes generated classes to disk and provides convenience methods for building classes.
*
* @author Graeme Rocher
* @since 1.0
*/
@Internal
public abstract class AbstractClassFileWriter implements Opcodes, OriginatingElements {
protected static final Type TYPE_ARGUMENT = Type.getType(Argument.class);
protected static final Type TYPE_ARGUMENT_ARRAY = Type.getType(Argument[].class);
protected static final String ZERO_ARGUMENTS_CONSTANT = "ZERO_ARGUMENTS";
protected static final String CONSTRUCTOR_NAME = "<init>";
protected static final String DESCRIPTOR_DEFAULT_CONSTRUCTOR = "()V";
protected static final Method METHOD_DEFAULT_CONSTRUCTOR = new Method(CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
protected static final Type TYPE_OBJECT = Type.getType(Object.class);
protected static final Type TYPE_CLASS = Type.getType(Class.class);
protected static final int DEFAULT_MAX_STACK = 13;
protected static final Type TYPE_GENERATED = Type.getType(Generated.class);
protected static final Map<String, String> NAME_TO_TYPE_MAP = new HashMap<>();
private static final Method METHOD_CREATE_ARGUMENT_SIMPLE = Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(
Argument.class,
"of",
Class.class,
String.class
)
);
private static final Method METHOD_CREATE_ARGUMENT_WITH_GENERICS = Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(
Argument.class,
"of",
Class.class,
String.class,
Argument[].class
)
);
private static final Method METHOD_CREATE_ARGUMENT_WITH_ANNOTATION_METADATA_GENERICS = Method.getMethod(
ReflectionUtils.getRequiredInternalMethod(
Argument.class,
"of",
Class.class,
String.class,
AnnotationMetadata.class,
Argument[].class
)
);
static {
NAME_TO_TYPE_MAP.put("void", "V");
NAME_TO_TYPE_MAP.put("boolean", "Z");
NAME_TO_TYPE_MAP.put("char", "C");
NAME_TO_TYPE_MAP.put("int", "I");
NAME_TO_TYPE_MAP.put("byte", "B");
NAME_TO_TYPE_MAP.put("long", "J");
NAME_TO_TYPE_MAP.put("double", "D");
NAME_TO_TYPE_MAP.put("float", "F");
NAME_TO_TYPE_MAP.put("short", "S");
}
private final OriginatingElements originatingElements;
Params: - originatingElement – The originating element
Deprecated: Use AbstractClassFileWriter(Element...)
instead
/**
* @param originatingElement The originating element
* @deprecated Use {@link #AbstractClassFileWriter(Element...)} instead
*/
@Deprecated
protected AbstractClassFileWriter(Element originatingElement) {
this(OriginatingElements.of(originatingElement));
}
Params: - originatingElements – The originating elements
/**
* @param originatingElements The originating elements
*/
protected AbstractClassFileWriter(Element... originatingElements) {
this(OriginatingElements.of(originatingElements));
}
Params: - originatingElements – The originating elements
/**
* @param originatingElements The originating elements
*/
protected AbstractClassFileWriter(OriginatingElements originatingElements) {
this.originatingElements = Objects.requireNonNull(originatingElements, "The originating elements cannot be null");
}
@NotNull
@Override
public Element[] getOriginatingElements() {
return originatingElements.getOriginatingElements();
}
@Override
public void addOriginatingElement(@NotNull Element element) {
originatingElements.addOriginatingElement(element);
}
Pushes type arguments onto the stack.
Params: - generatorAdapter – The generator adapter
- declaringElement – The declaring class element of the generics
- types – The type references
/**
* Pushes type arguments onto the stack.
*
* @param generatorAdapter The generator adapter
* @param declaringElement The declaring class element of the generics
* @param types The type references
*/
protected static void pushTypeArgumentElements(
GeneratorAdapter generatorAdapter,
TypedElement declaringElement,
Map<String, ClassElement> types) {
if (types == null || types.isEmpty()) {
generatorAdapter.visitInsn(ACONST_NULL);
return;
}
Set<String> visitedTypes = new HashSet<>(5);
pushTypeArgumentElements(generatorAdapter, declaringElement, types, visitedTypes);
}
private static void pushTypeArgumentElements(
GeneratorAdapter generatorAdapter,
TypedElement declaringElement,
Map<String, ClassElement> types,
Set<String> visitedTypes) {
if (visitedTypes.contains(declaringElement.getName())) {
generatorAdapter.getStatic(
TYPE_ARGUMENT,
ZERO_ARGUMENTS_CONSTANT,
TYPE_ARGUMENT_ARRAY
);
} else {
visitedTypes.add(declaringElement.getName());
int len = types.size();
// Build calls to Argument.create(...)
pushNewArray(generatorAdapter, Argument.class, len);
int i = 0;
for (Map.Entry<String, ClassElement> entry : types.entrySet()) {
// the array index
generatorAdapter.push(i);
String argumentName = entry.getKey();
ClassElement classElement = entry.getValue();
Object classReference = getTypeReference(classElement);
Map<String, ClassElement> typeArguments = null;
if (!classElement.getName().equals(declaringElement.getName())) {
typeArguments = classElement.getTypeArguments();
}
if (CollectionUtils.isNotEmpty(typeArguments)) {
buildArgumentWithGenerics(generatorAdapter, argumentName, classReference, classElement, typeArguments, visitedTypes);
} else {
buildArgument(generatorAdapter, argumentName, classReference);
}
// store the type reference
generatorAdapter.visitInsn(AASTORE);
// if we are not at the end of the array duplicate array onto the stack
if (i != (len - 1)) {
generatorAdapter.visitInsn(DUP);
}
i++;
}
}
}
Pushes type arguments onto the stack.
Params: - generatorAdapter – The generator adapter
- types – The type references
/**
* Pushes type arguments onto the stack.
*
* @param generatorAdapter The generator adapter
* @param types The type references
*/
protected static void pushTypeArguments(GeneratorAdapter generatorAdapter, Map<String, Object> types) {
if (types == null || types.isEmpty()) {
generatorAdapter.visitInsn(ACONST_NULL);
return;
}
int len = types.size();
// Build calls to Argument.create(...)
pushNewArray(generatorAdapter, Argument.class, len);
int i = 0;
for (Map.Entry<String, Object> entry : types.entrySet()) {
// the array index
generatorAdapter.push(i);
String typeParameterName = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
buildArgumentWithGenerics(generatorAdapter, typeParameterName, (Map) value);
} else {
buildArgument(generatorAdapter, typeParameterName, value);
}
// store the type reference
generatorAdapter.visitInsn(AASTORE);
// if we are not at the end of the array duplicate array onto the stack
if (i != (len - 1)) {
generatorAdapter.visitInsn(DUP);
}
i++;
}
}
Builds an argument instance.
Params: - generatorAdapter – The generator adapter.
- argumentName – The argument name
- objectType – The object type
/**
* Builds an argument instance.
*
* @param generatorAdapter The generator adapter.
* @param argumentName The argument name
* @param objectType The object type
*/
protected static void buildArgument(GeneratorAdapter generatorAdapter, String argumentName, Object objectType) {
// 1st argument: the type
generatorAdapter.push(getTypeReference(objectType));
// 2nd argument: the name
generatorAdapter.push(argumentName);
// Argument.create( .. )
invokeInterfaceStaticMethod(
generatorAdapter,
Argument.class,
METHOD_CREATE_ARGUMENT_SIMPLE
);
}
Builds generic type arguments recursively.
Params: - generatorAdapter – The generator adapter to use
- argumentName – The argument name
- typeReference – The type name
- classElement – The class element that declares the generics
- typeArguments – The nested type arguments
- visitedTypes –
/**
* Builds generic type arguments recursively.
*
* @param generatorAdapter The generator adapter to use
* @param argumentName The argument name
* @param typeReference The type name
* @param classElement The class element that declares the generics
* @param typeArguments The nested type arguments
* @param visitedTypes
*/
private static void buildArgumentWithGenerics(
GeneratorAdapter generatorAdapter, String argumentName,
Object typeReference,
ClassElement classElement,
Map<String, ClassElement> typeArguments, Set<String> visitedTypes) {
// 1st argument: the type
generatorAdapter.push(getTypeReference(typeReference));
// 2nd argument: the name
generatorAdapter.push(argumentName);
// 3rd argument, more generics
pushTypeArgumentElements(generatorAdapter, classElement, typeArguments, visitedTypes);
// Argument.create( .. )
invokeInterfaceStaticMethod(
generatorAdapter,
Argument.class,
METHOD_CREATE_ARGUMENT_WITH_GENERICS
);
}
This method should be replaced by the above method.
Params: - generatorAdapter – The
GeneratorAdapter
- argumentName – The argument name
- nestedTypeObject – The nested type object
/**
* This method should be replaced by the above method.
*
* @param generatorAdapter The {@link GeneratorAdapter}
* @param argumentName The argument name
* @param nestedTypeObject The nested type object
*/
static void buildArgumentWithGenerics(GeneratorAdapter generatorAdapter, String argumentName, Map nestedTypeObject) {
Map nestedTypes = null;
@SuppressWarnings("unchecked") Optional<Map.Entry> nestedEntry = nestedTypeObject.entrySet().stream().findFirst();
Object objectType;
if (nestedEntry.isPresent()) {
Map.Entry data = nestedEntry.get();
Object key = data.getKey();
Object map = data.getValue();
objectType = key;
if (map instanceof Map) {
nestedTypes = (Map) map;
}
} else {
throw new IllegalArgumentException("Must be a map with a single key containing the argument type and a map of generics as the value");
}
// 1st argument: the type
generatorAdapter.push(getTypeReference(objectType));
// 2nd argument: the name
generatorAdapter.push(argumentName);
// 3rd argument: generic types
boolean hasGenerics = nestedTypes != null && !nestedTypes.isEmpty();
if (hasGenerics) {
pushTypeArguments(generatorAdapter, nestedTypes);
}
// Argument.create( .. )
invokeInterfaceStaticMethod(
generatorAdapter,
Argument.class,
hasGenerics ? METHOD_CREATE_ARGUMENT_WITH_GENERICS : METHOD_CREATE_ARGUMENT_SIMPLE
);
}
Params: - owningType – The owning type
- declaringClassWriter – The declaring class writer
- generatorAdapter – The
GeneratorAdapter
- argumentTypes – The argument types
- argumentAnnotationMetadata – The argument annotation metadata
- genericTypes – The generic types
- loadTypeMethods – The load type methods
/**
* @param owningType The owning type
* @param declaringClassWriter The declaring class writer
* @param generatorAdapter The {@link GeneratorAdapter}
* @param argumentTypes The argument types
* @param argumentAnnotationMetadata The argument annotation metadata
* @param genericTypes The generic types
* @param loadTypeMethods The load type methods
*/
protected static void pushBuildArgumentsForMethod(
Type owningType,
ClassWriter declaringClassWriter,
GeneratorAdapter generatorAdapter,
Map<String, Object> argumentTypes,
Map<String, AnnotationMetadata> argumentAnnotationMetadata,
Map<String, Map<String, Object>> genericTypes,
Map<String, GeneratorAdapter> loadTypeMethods) {
int len = argumentTypes.size();
pushNewArray(generatorAdapter, Argument.class, len);
int i = 0;
for (Map.Entry<String, Object> entry : argumentTypes.entrySet()) {
// the array index position
generatorAdapter.push(i);
String argumentName = entry.getKey();
final Object value = entry.getValue();
Type argumentType;
if (value instanceof Map) {
// for generic types the info as passed with the class name being the key of the map
// bit of a hack and we need better data structures for this.
argumentType = getTypeReference(((Map) value).keySet().iterator().next());
} else {
argumentType = getTypeReference(value);
}
// 1st argument: The type
generatorAdapter.push(argumentType);
// 2nd argument: The argument name
generatorAdapter.push(argumentName);
// 3rd argument: The annotation metadata
AnnotationMetadata annotationMetadata = argumentAnnotationMetadata.get(argumentName);
if (annotationMetadata == null || annotationMetadata == AnnotationMetadata.EMPTY_METADATA) {
generatorAdapter.visitInsn(ACONST_NULL);
} else {
AnnotationMetadataWriter.instantiateNewMetadata(
owningType,
declaringClassWriter,
generatorAdapter,
(DefaultAnnotationMetadata) annotationMetadata,
loadTypeMethods
);
}
// 4th argument: The generic types
if (genericTypes != null && genericTypes.containsKey(argumentName)) {
Map<String, Object> types = genericTypes.get(argumentName);
pushTypeArguments(generatorAdapter, types);
} else {
generatorAdapter.visitInsn(ACONST_NULL);
}
// Argument.create( .. )
invokeInterfaceStaticMethod(
generatorAdapter,
Argument.class,
METHOD_CREATE_ARGUMENT_WITH_ANNOTATION_METADATA_GENERICS
);
// store the type reference
generatorAdapter.visitInsn(AASTORE);
// if we are not at the end of the array duplicate array onto the stack
if (i != (len - 1)) {
generatorAdapter.visitInsn(DUP);
}
i++;
}
}
Write the class to the target directory.
Params: - targetDir – The target directory
Throws: - IOException – if there is an error writing the file
/**
* Write the class to the target directory.
*
* @param targetDir The target directory
* @throws IOException if there is an error writing the file
*/
public void writeTo(File targetDir) throws IOException {
accept(newClassWriterOutputVisitor(targetDir));
}
Converts a map of class elements to type arguments.
Params: - typeArguments – The type arguments
Returns: The type arguments
/**
* Converts a map of class elements to type arguments.
*
* @param typeArguments The type arguments
* @return The type arguments
*/
@NotNull
protected Map<String, Object> toTypeArguments(@NotNull Map<String, ClassElement> typeArguments) {
Set<String> visitedTypes = new HashSet<>(5);
return toTypeArguments(typeArguments, visitedTypes);
}
@NotNull
private Map<String, Object> toTypeArguments(@NotNull Map<String, ClassElement> typeArguments, Set<String> visitedTypes) {
final LinkedHashMap<String, Object> map = new LinkedHashMap<>(typeArguments.size());
for (Map.Entry<String, ClassElement> entry : typeArguments.entrySet()) {
final ClassElement ce = entry.getValue();
String className = ce.getName();
if (!visitedTypes.contains(entry.getKey())) {
visitedTypes.add(entry.getKey());
final Map<String, ClassElement> subArgs = ce.getTypeArguments();
if (CollectionUtils.isNotEmpty(subArgs)) {
Map<String, Object> m = toTypeArguments(subArgs, visitedTypes);
if (CollectionUtils.isNotEmpty(m)) {
map.put(entry.getKey(), Collections.singletonMap(getTypeReference(ce), m));
} else {
map.put(entry.getKey(), Collections.singletonMap(entry.getKey(), className));
}
} else {
final Type typeReference = getTypeReference(ce);
map.put(entry.getKey(), typeReference);
}
}
}
return map;
}
Converts a map of class elements to type arguments.
Params: - parameters – The parametesr
Returns: The type arguments
/**
* Converts a map of class elements to type arguments.
*
* @param parameters The parametesr
* @return The type arguments
*/
@NotNull
protected Map<String, Map<String, Object>> toTypeArguments(ParameterElement... parameters) {
final LinkedHashMap<String, Map<String, Object>> map = new LinkedHashMap<>(parameters.length);
for (ParameterElement ce : parameters) {
final ClassElement type = ce.getType();
final Map<String, ClassElement> subArgs = type.getTypeArguments();
if (CollectionUtils.isNotEmpty(subArgs)) {
map.put(ce.getName(), toTypeArguments(subArgs));
}
}
return map;
}
Converts a parameters to type arguments.
Params: - parameters – The parameters
Returns: The type arguments
/**
* Converts a parameters to type arguments.
*
* @param parameters The parameters
* @return The type arguments
*/
@NotNull
protected Map<String, Object> toParameterTypes(ParameterElement... parameters) {
final LinkedHashMap<String, Object> map = new LinkedHashMap<>(parameters.length);
for (ParameterElement ce : parameters) {
final ClassElement type = ce.getType();
if (type == null) {
continue;
}
final Type typeReference = getTypeReference(type);
map.put(ce.getName(), typeReference);
}
return map;
}
Writes a method that returns a boolean value with the value supplied by the given supplier.
Params: - classWriter – The class writer
- methodName – The method name
- valueSupplier – The supplier
/**
* Writes a method that returns a boolean value with the value supplied by the given supplier.
*
* @param classWriter The class writer
* @param methodName The method name
* @param valueSupplier The supplier
*/
protected void writeBooleanMethod(ClassWriter classWriter, String methodName, Supplier<Boolean> valueSupplier) {
GeneratorAdapter isSingletonMethod = startPublicMethodZeroArgs(
classWriter,
boolean.class,
methodName
);
isSingletonMethod.loadThis();
isSingletonMethod.push(valueSupplier.get());
isSingletonMethod.returnValue();
isSingletonMethod.visitMaxs(1, 1);
isSingletonMethod.visitEnd();
}
Returns: The originating element
/**
* @return The originating element
*/
@Deprecated
public @Nullable Element getOriginatingElement() {
Element[] originatingElements = getOriginatingElements();
if (ArrayUtils.isNotEmpty(originatingElements)) {
return originatingElements[0];
} else {
return null;
}
}
Accept a ClassWriterOutputVisitor to write this writer to disk.
Params: - classWriterOutputVisitor – The
ClassWriterOutputVisitor
Throws: - IOException – if there is an error writing to disk
/**
* Accept a ClassWriterOutputVisitor to write this writer to disk.
*
* @param classWriterOutputVisitor The {@link ClassWriterOutputVisitor}
* @throws IOException if there is an error writing to disk
*/
public abstract void accept(ClassWriterOutputVisitor classWriterOutputVisitor) throws IOException;
Implements a method called "getInterceptedType" for the given type and class writer.
Params: - interceptedType – The intercepted type
- classWriter – The class writer
/**
* Implements a method called "getInterceptedType" for the given type and class writer.
* @param interceptedType The intercepted type
* @param classWriter The class writer
*/
protected void implementInterceptedTypeMethod(Type interceptedType, ClassWriter classWriter) {
GeneratorAdapter getTargetTypeMethod = startPublicMethodZeroArgs(
classWriter,
Class.class,
"getInterceptedType"
);
getTargetTypeMethod.loadThis();
getTargetTypeMethod.push(interceptedType);
getTargetTypeMethod.returnValue();
getTargetTypeMethod.visitMaxs(1, 1);
getTargetTypeMethod.visitEnd();
}
Returns the descriptor corresponding to the given class.
Params: - type – The type
Returns: The descriptor for the class
/**
* Returns the descriptor corresponding to the given class.
*
* @param type The type
* @return The descriptor for the class
*/
protected static String getTypeDescriptor(Object type) {
if (type instanceof Class) {
return Type.getDescriptor((Class) type);
} else if (type instanceof Type) {
return ((Type) type).getDescriptor();
} else {
String className = type.toString();
return getTypeDescriptor(className, new String[0]);
}
}
Returns the Type reference corresponding to the given class.
Params: - className – The class name
- genericTypes – The generic types
Returns: The Type
/**
* Returns the Type reference corresponding to the given class.
*
* @param className The class name
* @param genericTypes The generic types
* @return The {@link Type}
*/
protected static Type getTypeReferenceForName(String className, String... genericTypes) {
String referenceString = getTypeDescriptor(className, genericTypes);
return Type.getType(referenceString);
}
Return the type reference for a class.
Params: - type – The type
Returns: The Type
/**
* Return the type reference for a class.
*
* @param type The type
* @return The {@link Type}
*/
protected static Type getTypeReference(Object type) {
if (type instanceof Type) {
return (Type) type;
} else if (type instanceof Class) {
return Type.getType((Class) type);
} else if (type instanceof String) {
String className = type.toString();
String internalName = getInternalName(className);
if (className.endsWith("[]")) {
internalName = "[L" + internalName + ";";
}
return Type.getObjectType(internalName);
} else {
throw new IllegalArgumentException("Type reference [" + type + "] should be a Class or a String representing the class name");
}
}
Return the type reference for a class.
Params: - type – The type
Returns: The Type
/**
* Return the type reference for a class.
*
* @param type The type
* @return The {@link Type}
*/
protected static Type getTypeReference(TypedElement type) {
if (type.isPrimitive()) {
String internalName = NAME_TO_TYPE_MAP.get(type.getName());
if (type.isArray()) {
StringBuilder name = new StringBuilder(internalName);
for (int i = 0; i < type.getArrayDimensions(); i++) {
name.insert(0, "[");
}
return Type.getObjectType(name.toString());
} else {
return Type.getType(internalName);
}
} else {
String internalName = type.getName().replace('.', '/');
if (type.isArray()) {
StringBuilder name = new StringBuilder(internalName);
name.insert(0, "L");
for (int i = 0; i < type.getArrayDimensions(); i++) {
name.insert(0, "[");
}
name.append(";");
return Type.getObjectType(name.toString());
} else {
return Type.getObjectType(internalName);
}
}
}
Params: - fieldType – The field type
- injectMethodVisitor – The
MethodVisitor
/**
* @param fieldType The field type
* @param injectMethodVisitor The {@link MethodVisitor}
*/
protected static void pushBoxPrimitiveIfNecessary(Object fieldType, MethodVisitor injectMethodVisitor) {
if (fieldType instanceof Type) {
final Type t = (Type) fieldType;
final Optional<Class> pt = ClassUtils.getPrimitiveType(t.getClassName());
Class wrapperType = pt.map(ReflectionUtils::getWrapperType).orElse(null);
if (wrapperType != null) {
Type wrapper = Type.getType(wrapperType);
String primitiveName = t.getClassName();
String sig = wrapperType.getName() + " valueOf(" + primitiveName + ")";
org.objectweb.asm.commons.Method valueOfMethod = org.objectweb.asm.commons.Method.getMethod(sig);
injectMethodVisitor.visitMethodInsn(INVOKESTATIC, wrapper.getInternalName(), "valueOf", valueOfMethod.getDescriptor(), false);
}
} else {
Class wrapperType = AbstractClassFileWriter.getWrapperType(fieldType);
if (wrapperType != null) {
Class primitiveType = (Class) fieldType;
Type wrapper = Type.getType(wrapperType);
String primitiveName = primitiveType.getName();
String sig = wrapperType.getName() + " valueOf(" + primitiveName + ")";
org.objectweb.asm.commons.Method valueOfMethod = org.objectweb.asm.commons.Method.getMethod(sig);
injectMethodVisitor.visitMethodInsn(INVOKESTATIC, wrapper.getInternalName(), "valueOf", valueOfMethod.getDescriptor(), false);
}
}
}
Params: - methodVisitor – The
MethodVisitor
- type – The type
/**
* @param methodVisitor The {@link MethodVisitor}
* @param type The type
*/
protected static void pushCastToType(MethodVisitor methodVisitor, Object type) {
String internalName = getInternalNameForCast(type);
methodVisitor.visitTypeInsn(CHECKCAST, internalName);
Type primitiveType = null;
if (type instanceof Class) {
Class typeClass = (Class) type;
if (typeClass.isPrimitive()) {
primitiveType = Type.getType(typeClass);
}
} else if (type instanceof Type) {
final Optional<Class> pt = ClassUtils.getPrimitiveType(((Type) type).getClassName());
if (pt.isPresent()) {
primitiveType = Type.getType(pt.get());
}
}
if (primitiveType != null) {
org.objectweb.asm.commons.Method valueMethod = null;
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
valueMethod = org.objectweb.asm.commons.Method.getMethod("boolean booleanValue()");
break;
case Type.CHAR:
valueMethod = org.objectweb.asm.commons.Method.getMethod("char charValue()");
break;
case Type.BYTE:
valueMethod = org.objectweb.asm.commons.Method.getMethod("byte byteValue()");
break;
case Type.SHORT:
valueMethod = org.objectweb.asm.commons.Method.getMethod("short shortValue()");
break;
case Type.INT:
valueMethod = org.objectweb.asm.commons.Method.getMethod("int intValue()");
break;
case Type.LONG:
valueMethod = org.objectweb.asm.commons.Method.getMethod("long longValue()");
break;
case Type.DOUBLE:
valueMethod = org.objectweb.asm.commons.Method.getMethod("double doubleValue()");
break;
case Type.FLOAT:
valueMethod = org.objectweb.asm.commons.Method.getMethod("float floatValue()");
break;
default:
// no-ip
}
if (valueMethod != null) {
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, internalName, valueMethod.getName(), valueMethod.getDescriptor(), false);
}
}
}
Params: - methodVisitor – The
MethodVisitor
- type – The type
/**
* @param methodVisitor The {@link MethodVisitor}
* @param type The type
*/
protected static void pushReturnValue(MethodVisitor methodVisitor, Object type) {
if (type instanceof Class) {
Class typeClass = (Class) type;
if (typeClass.isPrimitive()) {
Type primitiveType = Type.getType(typeClass);
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
case Type.INT:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
methodVisitor.visitInsn(IRETURN);
break;
case Type.VOID:
methodVisitor.visitInsn(RETURN);
break;
case Type.LONG:
methodVisitor.visitInsn(LRETURN);
break;
case Type.DOUBLE:
methodVisitor.visitInsn(DRETURN);
break;
case Type.FLOAT:
methodVisitor.visitInsn(FRETURN);
break;
default:
//no-op
}
} else {
methodVisitor.visitInsn(ARETURN);
}
} else {
methodVisitor.visitInsn(ARETURN);
}
}
Params: - type – The type
Returns: The class
/**
* @param type The type
* @return The class
*/
protected static Class getWrapperType(Object type) {
if (isPrimitive(type)) {
return ReflectionUtils.getWrapperType((Class) type);
}
return null;
}
Params: - type – The type
Returns: Whether a type is primitive
/**
* @param type The type
* @return Whether a type is primitive
*/
protected static boolean isPrimitive(Object type) {
if (type instanceof Class) {
Class typeClass = (Class) type;
return typeClass.isPrimitive();
}
return false;
}
Params: - methodVisitor – The method visitor as
GeneratorAdapter
- methodName – The method name
- argumentTypes – The argument types
/**
* @param methodVisitor The method visitor as {@link GeneratorAdapter}
* @param methodName The method name
* @param argumentTypes The argument types
*/
protected static void pushMethodNameAndTypesArguments(GeneratorAdapter methodVisitor, String methodName, Collection<Object> argumentTypes) {
// and the method name
methodVisitor.visitLdcInsn(methodName);
int argTypeCount = argumentTypes.size();
if (!argumentTypes.isEmpty()) {
pushNewArray(methodVisitor, Class.class, argTypeCount);
Iterator<Object> argIterator = argumentTypes.iterator();
for (int i = 0; i < argTypeCount; i++) {
pushStoreTypeInArray(methodVisitor, i, argTypeCount, argIterator.next());
}
} else {
// no arguments
pushNewArray(methodVisitor, Class.class, 0);
}
}
Params: - methodVisitor – The method visitor as
GeneratorAdapter
- arrayType – The array class
- size – The size
/**
* @param methodVisitor The method visitor as {@link GeneratorAdapter}
* @param arrayType The array class
* @param size The size
*/
protected static void pushNewArray(GeneratorAdapter methodVisitor, Class arrayType, int size) {
// the size of the array
methodVisitor.push(size);
// define the array
methodVisitor.visitTypeInsn(ANEWARRAY, Type.getInternalName(arrayType));
// add a reference to the array on the stack
if (size > 0) {
methodVisitor.visitInsn(DUP);
}
}
Params: - methodVisitor – The method visitor as
GeneratorAdapter
- index – The index
- size – The size
- string – The string
/**
* @param methodVisitor The method visitor as {@link GeneratorAdapter}
* @param index The index
* @param size The size
* @param string The string
*/
protected static void pushStoreStringInArray(GeneratorAdapter methodVisitor, int index, int size, String string) {
// the array index position
methodVisitor.push(index);
// load the constant string
methodVisitor.push(string);
// store the string in the position
methodVisitor.visitInsn(AASTORE);
if (index != (size - 1)) {
// if we are not at the end of the array duplicate array onto the stack
methodVisitor.dup();
}
}
Params: - methodVisitor – The method visitor as
GeneratorAdapter
- index – The index
- size – The size
- runnable – The runnable
/**
* @param methodVisitor The method visitor as {@link GeneratorAdapter}
* @param index The index
* @param size The size
* @param runnable The runnable
*/
protected static void pushStoreInArray(GeneratorAdapter methodVisitor, int index, int size, Runnable runnable) {
// the array index position
methodVisitor.push(index);
// load the constant string
runnable.run();
// store the string in the position
methodVisitor.visitInsn(AASTORE);
if (index != (size - 1)) {
// if we are not at the end of the array duplicate array onto the stack
methodVisitor.dup();
}
}
Params: - methodVisitor – The method visitor as
GeneratorAdapter
- index – The index
- size – The size
- type – The type
/**
* @param methodVisitor The method visitor as {@link GeneratorAdapter}
* @param index The index
* @param size The size
* @param type The type
*/
protected static void pushStoreTypeInArray(GeneratorAdapter methodVisitor, int index, int size, Object type) {
// the array index position
methodVisitor.push(index);
// the type reference
if (type instanceof Class) {
Class typeClass = (Class) type;
if (typeClass.isPrimitive()) {
Type wrapperType = Type.getType(ReflectionUtils.getWrapperType(typeClass));
methodVisitor.visitFieldInsn(GETSTATIC, wrapperType.getInternalName(), "TYPE", Type.getDescriptor(Class.class));
} else {
methodVisitor.push(Type.getType(typeClass));
}
} else {
methodVisitor.push(getObjectType(type.toString()));
}
// store the type reference
methodVisitor.arrayStore(TYPE_CLASS);
// if we are not at the end of the array duplicate array onto the stack
if (index < (size - 1)) {
methodVisitor.dup();
}
}
Params: - types – The types
Returns: An array with the Type
of the objects
/**
* @param types The types
* @return An array with the {@link Type} of the objects
*/
protected Type[] getObjectTypes(Collection types) {
Type[] converted = new Type[types.size()];
Iterator iter = types.iterator();
for (int i = 0; i < converted.length; i++) {
Object type = iter.next();
converted[i] = getObjectType(type);
}
return converted;
}
Params: - type – The type
Returns: The Type
for the object type
/**
* @param type The type
* @return The {@link Type} for the object type
*/
protected static Type getObjectType(Object type) {
if (type instanceof Class) {
return Type.getType((Class) type);
} else if (type instanceof String) {
String className = type.toString();
String internalName = getTypeDescriptor(className);
return Type.getType(internalName);
} else {
throw new IllegalArgumentException("Type reference [" + type + "] should be a Class or a String representing the class name");
}
}
Params: - className – The class name
- genericTypes – The generic types
Returns: The type descriptor as String
/**
* @param className The class name
* @param genericTypes The generic types
* @return The type descriptor as String
*/
protected static String getTypeDescriptor(String className, String... genericTypes) {
if (NAME_TO_TYPE_MAP.containsKey(className)) {
return NAME_TO_TYPE_MAP.get(className);
} else {
String internalName = getInternalName(className);
StringBuilder start = new StringBuilder(40);
if (className.endsWith("[]")) {
start.append("[L").append(internalName);
} else {
start.append('L').append(internalName);
}
if (genericTypes != null && genericTypes.length > 0) {
start.append('<');
for (String genericType : genericTypes) {
start.append(getTypeDescriptor(genericType));
}
start.append('>');
}
return start.append(';').toString();
}
}
Params: - returnType – The return type
- argumentTypes – The argument types
Returns: The method descriptor
/**
* @param returnType The return type
* @param argumentTypes The argument types
* @return The method descriptor
*/
protected static String getMethodDescriptor(String returnType, String... argumentTypes) {
StringBuilder builder = new StringBuilder();
builder.append('(');
for (String argumentType : argumentTypes) {
builder.append(getTypeDescriptor(argumentType));
}
builder.append(')');
builder.append(getTypeDescriptor(returnType));
return builder.toString();
}
Params: - returnType – The return type
- argumentTypes – The argument types
Returns: The method descriptor
/**
* @param returnType The return type
* @param argumentTypes The argument types
* @return The method descriptor
*/
protected static String getMethodDescriptor(Object returnType, Collection<Object> argumentTypes) {
StringBuilder builder = new StringBuilder();
builder.append('(');
for (Object argumentType : argumentTypes) {
builder.append(getTypeDescriptor(argumentType));
}
builder.append(')');
builder.append(getTypeDescriptor(returnType));
return builder.toString();
}
Params: - returnTypeReference – The return type reference
- argReferenceTypes – The argument reference types
Returns: The method signature
/**
* @param returnTypeReference The return type reference
* @param argReferenceTypes The argument reference types
* @return The method signature
*/
protected static String getMethodSignature(String returnTypeReference, String... argReferenceTypes) {
StringBuilder builder = new StringBuilder();
builder.append('(');
for (String argumentType : argReferenceTypes) {
builder.append(argumentType);
}
builder.append(')');
builder.append(returnTypeReference);
return builder.toString();
}
Params: - argumentTypes – The argument types
Returns: The constructor descriptor
/**
* @param argumentTypes The argument types
* @return The constructor descriptor
*/
protected static String getConstructorDescriptor(Object... argumentTypes) {
return getConstructorDescriptor(Arrays.asList(argumentTypes));
}
Params: - argList – The argument list
Returns: The constructor descriptor
/**
* @param argList The argument list
* @return The constructor descriptor
*/
protected static String getConstructorDescriptor(Collection<Object> argList) {
StringBuilder builder = new StringBuilder();
builder.append('(');
for (Object argumentType : argList) {
builder.append(getTypeDescriptor(argumentType));
}
return builder.append(")V").toString();
}
Writes the class file to disk in the given directory.
Params: - targetDir – The target directory
- classWriter – The current class writer
- className – The class name
Throws: - IOException – if there is a problem writing the class to disk
/**
* Writes the class file to disk in the given directory.
*
* @param targetDir The target directory
* @param classWriter The current class writer
* @param className The class name
* @throws IOException if there is a problem writing the class to disk
*/
protected void writeClassToDisk(File targetDir, ClassWriter classWriter, String className) throws IOException {
if (targetDir != null) {
String fileName = className.replace('.', '/') + ".class";
File targetFile = new File(targetDir, fileName);
targetFile.getParentFile().mkdirs();
try (OutputStream outputStream = Files.newOutputStream(targetFile.toPath())) {
writeClassToDisk(outputStream, classWriter);
}
}
}
Params: - out – The output stream
- classWriter – The current class writer
Throws: - IOException – if there is a problem writing the class to disk
/**
* @param out The output stream
* @param classWriter The current class writer
* @throws IOException if there is a problem writing the class to disk
*/
protected void writeClassToDisk(OutputStream out, ClassWriter classWriter) throws IOException {
byte[] bytes = classWriter.toByteArray();
out.write(bytes);
}
Params: - classWriter – The current class writer
Returns: The GeneratorAdapter
for the constructor
/**
* @param classWriter The current class writer
* @return The {@link GeneratorAdapter} for the constructor
*/
protected GeneratorAdapter startConstructor(ClassVisitor classWriter) {
MethodVisitor defaultConstructor = classWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR, null, null);
return new GeneratorAdapter(defaultConstructor, ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
}
Params: - classWriter – The current class writer
- argumentTypes – The argument types
Returns: The GeneratorAdapter
for the constructor
/**
* @param classWriter The current class writer
* @param argumentTypes The argument types
* @return The {@link GeneratorAdapter} for the constructor
*/
protected GeneratorAdapter startConstructor(ClassVisitor classWriter, Object... argumentTypes) {
String descriptor = getConstructorDescriptor(argumentTypes);
return new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, descriptor, null, null), ACC_PUBLIC, CONSTRUCTOR_NAME, descriptor);
}
Params: - classWriter – The current class writer
- className – The class name
- superType – The super type
/**
* @param classWriter The current class writer
* @param className The class name
* @param superType The super type
*/
protected void startClass(ClassVisitor classWriter, String className, Type superType) {
classWriter.visit(V1_8, ACC_SYNTHETIC, className, null, superType.getInternalName(), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
}
Params: - classWriter – The current class writer
- className – The class name
- superType – The super type
/**
* @param classWriter The current class writer
* @param className The class name
* @param superType The super type
*/
protected void startPublicClass(ClassVisitor classWriter, String className, Type superType) {
classWriter.visit(V1_8, ACC_PUBLIC | ACC_SYNTHETIC, className, null, superType.getInternalName(), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
}
Params: - classWriter – The current class writer
- serviceType – The service type
- internalClassName – The class name
- superType – The super type
/**
* @param classWriter The current class writer
* @param serviceType The service type
* @param internalClassName The class name
* @param superType The super type
*/
protected void startService(ClassVisitor classWriter, Class<?> serviceType, String internalClassName, Type superType) {
startService(classWriter, serviceType.getName(), internalClassName, superType);
}
Params: - classWriter – The current class writer
- serviceName – The service name
- internalClassName – The class name
- superType – The super type
- interfaces – The interfaces
/**
* @param classWriter The current class writer
* @param serviceName The service name
* @param internalClassName The class name
* @param superType The super type
* @param interfaces The interfaces
*/
protected void startService(ClassVisitor classWriter, String serviceName, String internalClassName, Type superType, String... interfaces) {
classWriter.visit(V1_8, ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, internalClassName, null, superType.getInternalName(), interfaces);
AnnotationVisitor annotationVisitor = classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
annotationVisitor.visit("service", serviceName);
annotationVisitor.visitEnd();
}
Params: - classWriter – The current class writer
- className – The class name
- superType – The super type
/**
* @param classWriter The current class writer
* @param className The class name
* @param superType The super type
*/
protected void startFinalClass(ClassVisitor classWriter, String className, Type superType) {
classWriter.visit(V1_8, ACC_FINAL | ACC_SYNTHETIC, className, null, superType.getInternalName(), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
}
Starts a public final class.
Params: - classWriter – The current class writer
- className – The class name
- superType – The super type
/**
* Starts a public final class.
*
* @param classWriter The current class writer
* @param className The class name
* @param superType The super type
*/
protected void startPublicFinalClass(ClassVisitor classWriter, String className, Type superType) {
classWriter.visit(V1_8, ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, className, null, superType.getInternalName(), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
}
Params: - classWriter – The current class writer
- className – The class name
- superType – The super type
- genericSignature – The generic signature
/**
* @param classWriter The current class writer
* @param className The class name
* @param superType The super type
* @param genericSignature The generic signature
*/
protected void startClass(ClassWriter classWriter, String className, Type superType, String genericSignature) {
classWriter.visit(V1_8, ACC_SYNTHETIC, className, genericSignature, superType.getInternalName(), null);
classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
}
Params: - cv – The constructor visitor
- superClass – The super class
- argumentTypes – The argument types
/**
* @param cv The constructor visitor
* @param superClass The super class
* @param argumentTypes The argument types
*/
protected void invokeConstructor(MethodVisitor cv, Class superClass, Class... argumentTypes) {
try {
Type superType = Type.getType(superClass);
Type superConstructor = Type.getType(superClass.getDeclaredConstructor(argumentTypes));
cv.visitMethodInsn(INVOKESPECIAL,
superType.getInternalName(),
CONSTRUCTOR_NAME,
superConstructor.getDescriptor(),
false);
} catch (NoSuchMethodException e) {
throw new ClassGenerationException("Micronaut version on compile classpath doesn't match", e);
}
}
Params: - visitor – The interface visitor
- targetType – The target type
- method – The method
/**
* @param visitor The interface visitor
* @param targetType The target type
* @param method The method
*/
protected static void invokeInterfaceStaticMethod(MethodVisitor visitor, Class targetType, Method method) {
Type type = Type.getType(targetType);
String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
: type.getInternalName();
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, method.getName(),
method.getDescriptor(), true);
}
Params: - classWriter – The current class writer
- returnType – The return type
- methodName – The method name
Returns: TheThe GeneratorAdapter
for the method
/**
* @param classWriter The current class writer
* @param returnType The return type
* @param methodName The method name
* @return TheThe {@link GeneratorAdapter} for the method
*/
protected GeneratorAdapter startPublicMethodZeroArgs(ClassWriter classWriter, Class returnType, String methodName) {
Type methodType = Type.getMethodType(Type.getType(returnType));
return new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC, methodName, methodType.getDescriptor(), null, null), ACC_PUBLIC, methodName, methodType.getDescriptor());
}
Params: - classWriter – The current class writer
- returnType – The return type
- methodName – The method name
Returns: TheThe GeneratorAdapter
for the method
/**
* @param classWriter The current class writer
* @param returnType The return type
* @param methodName The method name
* @return TheThe {@link GeneratorAdapter} for the method
*/
protected GeneratorAdapter startPublicFinalMethodZeroArgs(ClassWriter classWriter, Class returnType, String methodName) {
Type methodType = Type.getMethodType(Type.getType(returnType));
return new GeneratorAdapter(
classWriter.visitMethod(
ACC_PUBLIC | ACC_FINAL,
methodName,
methodType.getDescriptor(),
null,
null
), ACC_PUBLIC, methodName, methodType.getDescriptor());
}
Params: - className – The class name
Returns: The internal name
/**
* @param className The class name
* @return The internal name
*/
protected static String getInternalName(String className) {
String newClassName = className.replace('.', '/');
if (newClassName.endsWith("[]")) {
return newClassName.substring(0, newClassName.length() - 2);
}
return newClassName;
}
Params: - type – The type
Returns: the internal name for cast
/**
* @param type The type
* @return the internal name for cast
*/
protected static String getInternalNameForCast(Object type) {
if (type instanceof Class) {
Class typeClass = (Class) type;
if (typeClass.isPrimitive()) {
typeClass = ReflectionUtils.getWrapperType(typeClass);
}
return Type.getInternalName(typeClass);
} else if (type instanceof Type) {
final Type t = (Type) type;
final Optional<Class> pt = ClassUtils.getPrimitiveType(t.getClassName());
if (pt.isPresent()) {
return Type.getInternalName(ReflectionUtils.getWrapperType(pt.get()));
} else {
return t.getInternalName();
}
} else {
String className = type.toString();
if (className.endsWith("[]")) {
return getTypeDescriptor(type);
} else {
return getInternalName(className);
}
}
}
Params: - className – The class name
Returns: The class file name
/**
* @param className The class name
* @return The class file name
*/
protected String getClassFileName(String className) {
return className.replace('.', File.separatorChar) + ".class";
}
Params: - compilationDir – The compilation directory
Returns: The directory class writer output visitor
/**
* @param compilationDir The compilation directory
* @return The directory class writer output visitor
*/
protected ClassWriterOutputVisitor newClassWriterOutputVisitor(File compilationDir) {
return new DirectoryClassWriterOutputVisitor(compilationDir);
}
Params: - overriddenMethodGenerator – The overriden method generator
/**
* @param overriddenMethodGenerator The overriden method generator
*/
protected void returnVoid(GeneratorAdapter overriddenMethodGenerator) {
overriddenMethodGenerator.pop();
overriddenMethodGenerator.visitInsn(RETURN);
}
Params: - classWriter – The current class writer
Returns: The GeneratorAdapter
/**
* @param classWriter The current class writer
* @return The {@link GeneratorAdapter}
*/
protected GeneratorAdapter visitStaticInitializer(ClassVisitor classWriter) {
MethodVisitor mv = classWriter.visitMethod(ACC_STATIC, "<clinit>", DESCRIPTOR_DEFAULT_CONSTRUCTOR, null, null);
return new GeneratorAdapter(mv, ACC_STATIC, "<clinit>", DESCRIPTOR_DEFAULT_CONSTRUCTOR);
}
Params: - writer – The class writer
- methodName – The method name
- returnType – The return type
- argumentTypes – The argument types
Returns: The GeneratorAdapter
/**
* @param writer The class writer
* @param methodName The method name
* @param returnType The return type
* @param argumentTypes The argument types
* @return The {@link GeneratorAdapter}
*/
protected GeneratorAdapter startPublicMethod(ClassWriter writer, String methodName, String returnType, String... argumentTypes) {
return new GeneratorAdapter(writer.visitMethod(
ACC_PUBLIC,
methodName,
getMethodDescriptor(returnType, argumentTypes),
null,
null
), ACC_PUBLIC,
methodName,
getMethodDescriptor(returnType, argumentTypes));
}
Params: - writer – The class writer
- methodName – The method name
- returnType – The return type
- argumentTypes – The argument types
Returns: The GeneratorAdapter
/**
* @param writer The class writer
* @param methodName The method name
* @param returnType The return type
* @param argumentTypes The argument types
* @return The {@link GeneratorAdapter}
*/
protected GeneratorAdapter startProtectedMethod(ClassWriter writer, String methodName, String returnType, String... argumentTypes) {
return new GeneratorAdapter(writer.visitMethod(
ACC_PROTECTED,
methodName,
getMethodDescriptor(returnType, argumentTypes),
null,
null
), ACC_PROTECTED,
methodName,
getMethodDescriptor(returnType, argumentTypes));
}
Generates a service discovery for the given class name and file.
Params: - className – The class name
- generatedFile – The generated file
Throws: - IOException – An exception if an error occurs
/**
* Generates a service discovery for the given class name and file.
*
* @param className The class name
* @param generatedFile The generated file
* @throws IOException An exception if an error occurs
*/
protected void generateServiceDescriptor(String className, GeneratedFile generatedFile) throws IOException {
CharSequence contents = generatedFile.getTextContent();
if (contents != null) {
String[] entries = contents.toString().split("\\n");
if (!Arrays.asList(entries).contains(className)) {
try (BufferedWriter w = new BufferedWriter(generatedFile.openWriter())) {
w.newLine();
w.write(className);
}
}
} else {
try (BufferedWriter w = new BufferedWriter(generatedFile.openWriter())) {
w.write(className);
}
}
}
Push the instantiation of the given type.
Params: - generatorAdapter – The generator adaptor
- typeToInstantiate – The type to instantiate.
/**
* Push the instantiation of the given type.
*
* @param generatorAdapter The generator adaptor
* @param typeToInstantiate The type to instantiate.
*/
protected void pushNewInstance(GeneratorAdapter generatorAdapter, Type typeToInstantiate) {
generatorAdapter.newInstance(typeToInstantiate);
generatorAdapter.dup();
generatorAdapter.invokeConstructor(typeToInstantiate, METHOD_DEFAULT_CONSTRUCTOR);
}
}