Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.strobel.reflection.emit.MethodBuilder Maven / Gradle / Ivy
/*
* MethodBuilder.java
*
* Copyright (c) 2012 Mike Strobel
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.reflection.emit;
import com.strobel.annotations.NotNull;
import com.strobel.core.ArrayUtilities;
import com.strobel.core.ReadOnlyList;
import com.strobel.core.VerifyArgument;
import com.strobel.reflection.*;
import com.strobel.util.EmptyArrayCache;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* @author Mike Strobel
*/
@SuppressWarnings({"PackageVisibleField", "unchecked"})
public final class MethodBuilder extends MethodInfo {
private final String _name;
private final TypeBuilder> _declaringType;
private final int _modifiers;
private SignatureType _signatureType;
private TypeList _thrownTypes;
private boolean _isFinished;
private ReadOnlyList> _annotations;
private byte[] _body;
private int _numberOfExceptions;
private __ExceptionInstance[] _exceptions;
private Object _defaultValue;
GenericParameterBuilder>[] genericParameterBuilders;
ParameterBuilder[] parameterBuilders;
CodeGenerator generator;
MethodInfo generatedMethod;
MethodBuilder(
final String name,
final int modifiers,
final Type> returnType,
final TypeList parameterTypes,
final TypeList thrownTypes,
final TypeBuilder> declaringType) {
_name = VerifyArgument.notNullOrWhitespace(name, "name");
_modifiers = modifiers;
_signatureType = new SignatureType(
returnType != null ? returnType : PrimitiveTypes.Void,
parameterTypes != null ? parameterTypes : TypeList.empty()
);
_thrownTypes = thrownTypes != null ? thrownTypes : TypeList.empty();
_declaringType = VerifyArgument.notNull(declaringType, "declaringType");
_annotations = ReadOnlyList.emptyList();
setSignature(returnType, parameterTypes);
}
final void verifyNotGeneric() {
if (isGenericMethod() && !isGenericMethodDefinition()) {
throw Error.methodIsGeneric();
}
}
final void verifyNotAbstract() {
if (isAbstract()) {
throw Error.abstractMethodCannotHaveBody();
}
}
public CodeGenerator getCodeGenerator() {
verifyNotGeneric();
verifyNotAbstract();
if (generator == null) {
generator = new CodeGenerator(this);
}
return generator;
}
public CodeGenerator getCodeGenerator(final int initialSize) {
verifyNotGeneric();
verifyNotAbstract();
if (generator == null) {
generator = new CodeGenerator(this, initialSize);
}
return generator;
}
@Override
public String getName() {
return _name;
}
@Override
public Type> getReturnType() {
return _signatureType.getReturnType();
}
@Override
public SignatureType getSignatureType() {
return _signatureType;
}
@Override
public Method getRawMethod() {
_declaringType.verifyCreated();
return generatedMethod.getRawMethod();
}
@Override
public Object getDefaultValue() {
return _defaultValue;
}
public void setDefaultValue(final Object value) {
if (!_declaringType.isInterface() || !Types.Annotation.isAssignableFrom(_declaringType)) {
throw Error.onlyAnnotationMethodsCanHaveDefaultValues();
}
_defaultValue = value;
}
@Override
public TypeBuilder> getDeclaringType() {
return _declaringType;
}
@Override
public int getModifiers() {
return _modifiers;
}
@Override
public ParameterList getParameters() {
return _declaringType.isCreated() ? generatedMethod.getParameters() : createParameters();
}
final ParameterList createParameters() {
final List pb = this.getDefinedParameters();
final ParameterInfo[] p = new ParameterInfo[pb.size()];
for (int i = 0; i < p.length; i++) {
final ParameterBuilder b = pb.get(i);
p[i] = new ParameterInfo(b.getName(), b.getPosition(), b.getParameterType());
}
return new ParameterList(p);
}
@Override
public TypeList getThrownTypes() {
return _thrownTypes;
}
public TypeList getParameterTypes() {
return _signatureType.getParameterTypes();
}
public List getDefinedParameters() {
return ArrayUtilities.asUnmodifiableList(parameterBuilders);
}
public boolean isTypeCreated() {
return _declaringType.isCreated();
}
public boolean isFinished() {
return _isFinished;
}
public void setReturnType(final Type> type) {
verifyCodeGeneratorNotCreated();
setSignature(type, null);
}
final void verifyCodeGeneratorNotCreated() {
if (generator != null) {
throw Error.cannotModifyMethodAfterCallingGetGenerator();
}
}
public void setSignature(final Type> returnType, final TypeList parameterTypes) {
verifyNotGeneric();
Type> newReturnType = _signatureType.getReturnType();
TypeList newParameterTypes = _signatureType.getParameterTypes();
if (returnType != null) {
newReturnType = returnType;
}
if (parameterTypes != null) {
newParameterTypes = parameterTypes;
parameterBuilders = new ParameterBuilder[parameterTypes.size()];
for (int i = 0, n = parameterTypes.size(); i < n; i++) {
parameterBuilders[i] = new ParameterBuilder(
this,
i,
null,
parameterTypes.get(i)
);
}
}
if (!newReturnType.isEquivalentTo(_signatureType.getReturnType()) ||
!newParameterTypes.isEquivalentTo(_signatureType.getParameterTypes())) {
_signatureType = new SignatureType(newReturnType, newParameterTypes);
}
invalidateCaches();
}
public void setParameters(final TypeList types) {
verifyCodeGeneratorNotCreated();
setSignature(null, types);
}
public void setThrownTypes(final TypeList types) {
verifyCodeGeneratorNotCreated();
_thrownTypes = types != null ? types : TypeList.empty();
invalidateCaches();
}
@Override
public Type getReflectedType() {
return _declaringType;
}
public void addCustomAnnotation(final AnnotationBuilder annotation) {
VerifyArgument.notNull(annotation, "annotation");
final AnnotationBuilder[] newAnnotations = new AnnotationBuilder[this._annotations.size() + 1];
_annotations.toArray(newAnnotations);
newAnnotations[this._annotations.size()] = annotation;
_annotations = new ReadOnlyList>(newAnnotations);
}
public ReadOnlyList> getCustomAnnotations() {
return _annotations;
}
@Override
public T getAnnotation(final Class annotationClass) {
_declaringType.verifyCreated();
return generatedMethod.getAnnotation(annotationClass);
}
@NotNull
@Override
public Annotation[] getAnnotations() {
_declaringType.verifyCreated();
return generatedMethod.getAnnotations();
}
@NotNull
@Override
public Annotation[] getDeclaredAnnotations() {
_declaringType.verifyCreated();
return generatedMethod.getDeclaredAnnotations();
}
@Override
public boolean isAnnotationPresent(final Class extends Annotation> annotationClass) {
_declaringType.verifyCreated();
return generatedMethod.isAnnotationPresent(annotationClass);
}
@Override
public boolean isGenericMethod() {
return !ArrayUtilities.isNullOrEmpty(genericParameterBuilders);
}
@Override
public boolean isGenericMethodDefinition() {
return isGenericMethod();
}
@Override
public TypeList getGenericMethodParameters() {
if (ArrayUtilities.isNullOrEmpty(genericParameterBuilders)) {
return TypeList.empty();
}
return Type.list(genericParameterBuilders);
}
@Override
public MethodInfo getErasedMethodDefinition() {
if (_declaringType.isCreated()) {
return generatedMethod.getErasedMethodDefinition();
}
return super.getErasedMethodDefinition();
}
@Override
public StringBuilder appendDescription(final StringBuilder sb) {
StringBuilder s = new StringBuilder();
for (final javax.lang.model.element.Modifier modifier : Flags.asModifierSet(getModifiers())) {
s.append(modifier.toString());
s.append(' ');
}
if (isGenericMethodDefinition()) {
final GenericParameterBuilder>[] genericParameters = genericParameterBuilders;
s.append('<');
for (int i = 0, n = genericParameters.length; i < n; i++) {
if (i != 0) {
s.append(", ");
}
s = genericParameters[i].appendSimpleDescription(s);
}
s.append('>');
s.append(' ');
}
Type returnType = getReturnType();
while (returnType.isWildcardType()) {
returnType = returnType.getExtendsBound();
}
if (returnType.isGenericParameter()) {
s.append(returnType.getName());
}
else {
s = returnType.appendSimpleDescription(s);
}
s.append(' ');
s.append(getName());
s.append('(');
final ParameterList parameters = getParameters();
for (int i = 0, n = parameters.size(); i < n; ++i) {
final ParameterInfo p = parameters.get(i);
if (i != 0) {
s.append(", ");
}
Type parameterType = p.getParameterType();
while (parameterType.isWildcardType()) {
parameterType = parameterType.getExtendsBound();
}
if (parameterType.isGenericParameter()) {
s.append(parameterType.getName());
}
else {
s = parameterType.appendSimpleDescription(s);
}
}
s.append(')');
final TypeList thrownTypes = getThrownTypes();
if (!thrownTypes.isEmpty()) {
s.append(" throws ");
for (int i = 0, n = thrownTypes.size(); i < n; ++i) {
final Type t = thrownTypes.get(i);
if (i != 0) {
s.append(", ");
}
s = t.appendBriefDescription(s);
}
}
return s;
}
@Override
public StringBuilder appendSimpleDescription(final StringBuilder sb) {
StringBuilder s = new StringBuilder();
for (final javax.lang.model.element.Modifier modifier : Flags.asModifierSet(getModifiers())) {
s.append(modifier.toString());
s.append(' ');
}
if (isGenericMethodDefinition()) {
final GenericParameterBuilder>[] genericParameters = genericParameterBuilders;
s.append('<');
for (int i = 0, n = genericParameters.length; i < n; i++) {
if (i != 0) {
s.append(", ");
}
s = genericParameters[i].appendSimpleDescription(s);
}
s.append('>');
s.append(' ');
}
s = getReturnType().appendSimpleDescription(s);
s.append(' ');
s.append(getName());
s.append('(');
final ParameterBuilder[] parameters = parameterBuilders;
for (int i = 0, n = parameters.length; i < n; ++i) {
final ParameterBuilder p = parameters[i];
if (i != 0) {
s.append(", ");
}
s = p.getParameterType().appendSimpleDescription(s);
}
s.append(')');
final TypeList thrownTypes = getThrownTypes();
if (!thrownTypes.isEmpty()) {
s.append(" throws ");
for (int i = 0, n = thrownTypes.size(); i < n; ++i) {
final Type t = thrownTypes.get(i);
if (i != 0) {
s.append(", ");
}
s = t.appendSimpleDescription(s);
}
}
return s;
}
@Override
public StringBuilder appendErasedSignature(final StringBuilder sb) {
StringBuilder s = sb;
s.append('(');
final TypeList parameterTypes = getParameterTypes();
for (int i = 0, n = parameterTypes.size(); i < n; ++i) {
s = parameterTypes.get(i).appendErasedSignature(s);
}
s.append(')');
s = getReturnType().appendErasedSignature(s);
return s;
}
@Override
public StringBuilder appendSignature(final StringBuilder sb) {
StringBuilder s = sb;
if (isGenericMethod()) {
final GenericParameterBuilder>[] genericParameters = genericParameterBuilders;
final int count = genericParameters.length;
if (count > 0) {
s.append('<');
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < count; ++i) {
final Type type = genericParameters[i];
s = type.appendGenericSignature(s);
}
s.append('>');
}
}
s.append('(');
final TypeList parameterTypes = getParameterTypes();
for (int i = 0, n = parameterTypes.size(); i < n; ++i) {
s = parameterTypes.get(i).appendSignature(s);
}
s.append(')');
s = getReturnType().appendSignature(s);
return s;
}
public GenericParameterBuilder>[] defineGenericParameters(final String... names) {
VerifyArgument.notEmpty(names, "names");
if (genericParameterBuilders != null) {
throw Error.genericParametersAlreadySet();
}
final GenericParameterBuilder>[] parameters = new GenericParameterBuilder>[names.length];
for (int i = 0, n = names.length; i < n; i++) {
final String name = names[i];
if (name == null) {
throw new IllegalArgumentException("Names array contains one or more null elements.");
}
parameters[i] = new GenericParameterBuilder<>(new TypeBuilder(name, i, this));
}
genericParameterBuilders = parameters;
return genericParameterBuilders;
}
public ParameterBuilder defineParameter(final int position, final String name) {
verifyCodeGeneratorNotCreated();
VerifyArgument.isNonNegative(position, "position");
verifyNotGeneric();
_declaringType.verifyNotCreated();
final TypeList parameterTypes = _signatureType.getParameterTypes();
if (parameterTypes == null || position >= parameterTypes.size()) {
throw new IllegalArgumentException("Position is out of range.");
}
final ParameterBuilder parameterBuilder = parameterBuilders[position];
parameterBuilder.setName(name);
return parameterBuilder;
}
public void createMethodBody(final byte[] bytecode, final int size) {
verifyNotGeneric();
if (isFinished()) {
throw Error.methodIsFinished();
}
_declaringType.verifyNotCreated();
if (bytecode != null) {
VerifyArgument.inRange(0, bytecode.length, size, "size");
}
if (bytecode == null) {
_body = null;
return;
}
_body = Arrays.copyOf(bytecode, size);
_isFinished = true;
}
final byte[] getBody() {
return _body;
}
final __ExceptionInstance[] getExceptionInstances() {
return _exceptions;
}
final int getNumberOfExceptions() {
return _numberOfExceptions;
}
final void createMethodBodyHelper(final CodeGenerator code) {
VerifyArgument.notNull(code, "code");
final __ExceptionInfo[] exceptions;
// final Type>[] unhandledExceptions;
int counter = 0;
int[] filterAddresses;
int[] catchAddresses;
int[] catchEndAddresses;
Type[] catchClass;
int[] exceptionType;
int numberOfCatches;
int startAddress, endAddress;
_declaringType.verifyNotCreated();
if (_isFinished) {
throw Error.methodIsFinished();
}
if (code.methodBuilder != this && code.methodBuilder != null) {
throw Error.bytecodeGeneratorNotOwnedByMethodBuilder();
}
if (code.scopeTree._openScopeCount != 0) {
throw Error.methodHasOpenLocalScope();
}
_body = code.bakeByteArray();
exceptions = code.getExceptions();
/*
unhandledExceptions = code.getUnhandledCheckedExceptions();
for (final Type> unhandledExceptionType : unhandledExceptions) {
if (!_thrownTypes.containsTypeAssignableFrom(unhandledExceptionType)) {
throw Error.checkedExceptionUnhandled(unhandledExceptionType);
}
}
*/
_numberOfExceptions = calculateNumberOfExceptions(exceptions);
if (_numberOfExceptions > 0) {
_exceptions = new __ExceptionInstance[_numberOfExceptions];
for (final __ExceptionInfo exception : exceptions) {
filterAddresses = exception.getFilterAddresses();
catchAddresses = exception.getCatchAddresses();
catchEndAddresses = exception.getCatchEndAddresses();
catchClass = exception.getCatchClass();
numberOfCatches = exception.getNumberOfCatches();
startAddress = exception.getStartAddress();
endAddress = exception.getEndAddress();
exceptionType = exception.getExceptionTypes();
for (int j = 0; j < numberOfCatches; j++) {
int tkExceptionClass = 0;
if (catchClass[j] != null) {
tkExceptionClass = _declaringType.getTypeToken(catchClass[j]);
}
switch (exceptionType[j]) {
case __ExceptionInfo.None:
case __ExceptionInfo.Filter:
_exceptions[counter++] = new __ExceptionInstance(
startAddress,
endAddress,
filterAddresses[j],
catchAddresses[j],
catchEndAddresses[j],
exceptionType[j],
tkExceptionClass
);
break;
case __ExceptionInfo.Finally:
_exceptions[counter++] = new __ExceptionInstance(
startAddress,
exception.getEndAddress(),
filterAddresses[j],
catchAddresses[j],
catchEndAddresses[j],
exceptionType[j],
tkExceptionClass
);
break;
}
}
}
}
else {
_exceptions = EmptyArrayCache.fromElementType(__ExceptionInstance.class);
}
_isFinished = true;
}
private static int calculateNumberOfExceptions(final __ExceptionInfo[] exceptions) {
int numberOfExceptions = 0;
if (exceptions == null) {
return 0;
}
for (final __ExceptionInfo exception : exceptions) {
numberOfExceptions += exception.getNumberOfCatches();
}
return numberOfExceptions;
}
final void releaseBakedStructures() {
_body = null;
}
}
@SuppressWarnings("PackageVisibleField")
final class __ExceptionInstance {
int exceptionClass;
int startAddress;
int endAddress;
int filterAddress;
int handleAddress;
int handleEndAddress;
int type;
__ExceptionInstance(
final int start,
final int end,
final int filterAddress,
final int handle,
final int handleEnd,
final int type,
final int exceptionClass) {
this.startAddress = start;
this.endAddress = end;
this.filterAddress = filterAddress;
this.handleAddress = handle;
this.handleEndAddress = handleEnd;
this.type = type;
this.exceptionClass = exceptionClass;
}
@Override
public boolean equals(final Object obj) {
if (obj != null && (obj instanceof __ExceptionInstance)) {
final __ExceptionInstance that = (__ExceptionInstance)obj;
return that.exceptionClass == exceptionClass &&
that.startAddress == startAddress &&
that.endAddress == endAddress &&
that.filterAddress == filterAddress &&
that.handleAddress == handleAddress &&
that.handleEndAddress == handleEndAddress;
}
else {
return false;
}
}
@Override
public int hashCode() {
return exceptionClass ^ startAddress ^ endAddress ^ filterAddress ^ handleAddress ^ handleEndAddress ^ type;
}
}