Skip to content

Commit

Permalink
Added a method call instrumentation that allows to create explicit ca…
Browse files Browse the repository at this point in the history
…lls.
  • Loading branch information
Rafael Winterhalter committed Feb 9, 2015
1 parent 0a06194 commit 2736224
Show file tree
Hide file tree
Showing 13 changed files with 2,091 additions and 77 deletions.
Expand Up @@ -41,17 +41,17 @@ public abstract class FieldAccessor implements Instrumentation {
* {@code true} if the runtime type of the field's value should be considered when a field * {@code true} if the runtime type of the field's value should be considered when a field
* is accessed. * is accessed.
*/ */
protected final boolean considerRuntimeType; protected final boolean dynamicallyTyped;


/** /**
* Creates a new field accessor. * Creates a new field accessor.
* *
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
*/ */
protected FieldAccessor(Assigner assigner, boolean considerRuntimeType) { protected FieldAccessor(Assigner assigner, boolean dynamicallyTyped) {
this.assigner = assigner; this.assigner = assigner;
this.considerRuntimeType = considerRuntimeType; this.dynamicallyTyped = dynamicallyTyped;
} }


/** /**
Expand Down Expand Up @@ -120,7 +120,7 @@ protected ByteCodeAppender.Size applyGetter(MethodVisitor methodVisitor,
MethodDescription methodDescription) { MethodDescription methodDescription) {
StackManipulation stackManipulation = assigner.assign(fieldDescription.getFieldType(), StackManipulation stackManipulation = assigner.assign(fieldDescription.getFieldType(),
methodDescription.getReturnType(), methodDescription.getReturnType(),
considerRuntimeType); dynamicallyTyped);
if (!stackManipulation.isValid()) { if (!stackManipulation.isValid()) {
throw new IllegalStateException("Getter type of " + methodDescription + " is not compatible with " + fieldDescription); throw new IllegalStateException("Getter type of " + methodDescription + " is not compatible with " + fieldDescription);
} }
Expand Down Expand Up @@ -150,7 +150,7 @@ protected ByteCodeAppender.Size applySetter(MethodVisitor methodVisitor,
MethodDescription methodDescription) { MethodDescription methodDescription) {
StackManipulation stackManipulation = assigner.assign(methodDescription.getParameterTypes().get(0), StackManipulation stackManipulation = assigner.assign(methodDescription.getParameterTypes().get(0),
fieldDescription.getFieldType(), fieldDescription.getFieldType(),
considerRuntimeType); dynamicallyTyped);
if (!stackManipulation.isValid()) { if (!stackManipulation.isValid()) {
throw new IllegalStateException("Setter type of " + methodDescription + " is not compatible with " + fieldDescription); throw new IllegalStateException("Setter type of " + methodDescription + " is not compatible with " + fieldDescription);
} else if (fieldDescription.isFinal()) { } else if (fieldDescription.isFinal()) {
Expand Down Expand Up @@ -209,13 +209,13 @@ private ByteCodeAppender.Size apply(MethodVisitor methodVisitor,
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return this == other || !(other == null || getClass() != other.getClass()) return this == other || !(other == null || getClass() != other.getClass())
&& considerRuntimeType == ((FieldAccessor) other).considerRuntimeType && dynamicallyTyped == ((FieldAccessor) other).dynamicallyTyped
&& assigner.equals(((FieldAccessor) other).assigner); && assigner.equals(((FieldAccessor) other).assigner);
} }


@Override @Override
public int hashCode() { public int hashCode() {
return 31 * assigner.hashCode() + (considerRuntimeType ? 1 : 0); return 31 * assigner.hashCode() + (dynamicallyTyped ? 1 : 0);
} }


/** /**
Expand Down Expand Up @@ -481,10 +481,10 @@ public static interface AssignerConfigurable extends Instrumentation {
* and runtime type use configuration. * and runtime type use configuration.
* *
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
* @return This field accessor with the given assigner and runtime type use configuration. * @return This field accessor with the given assigner and runtime type use configuration.
*/ */
Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType); Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped);
} }


/** /**
Expand Down Expand Up @@ -564,14 +564,14 @@ protected static class ForUnnamedField extends FieldAccessor implements OwnerTyp
* Creates a new field accessor instrumentation. * Creates a new field accessor instrumentation.
* *
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
* @param fieldNameExtractor The field name extractor to use. * @param fieldNameExtractor The field name extractor to use.
*/ */
protected ForUnnamedField(Assigner assigner, protected ForUnnamedField(Assigner assigner,
boolean considerRuntimeType, boolean dynamicallyTyped,
FieldNameExtractor fieldNameExtractor) { FieldNameExtractor fieldNameExtractor) {
this(assigner, this(assigner,
considerRuntimeType, dynamicallyTyped,
fieldNameExtractor, fieldNameExtractor,
FieldLocator.ForInstrumentedTypeHierarchy.Factory.INSTANCE); FieldLocator.ForInstrumentedTypeHierarchy.Factory.INSTANCE);
} }
Expand All @@ -580,23 +580,23 @@ protected ForUnnamedField(Assigner assigner,
* Creates a new field accessor instrumentation. * Creates a new field accessor instrumentation.
* *
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
* @param fieldNameExtractor The field name extractor to use. * @param fieldNameExtractor The field name extractor to use.
* @param fieldLocatorFactory A factory that will produce a field locator that will be used to find locate * @param fieldLocatorFactory A factory that will produce a field locator that will be used to find locate
* a field to be accessed. * a field to be accessed.
*/ */
protected ForUnnamedField(Assigner assigner, protected ForUnnamedField(Assigner assigner,
boolean considerRuntimeType, boolean dynamicallyTyped,
FieldNameExtractor fieldNameExtractor, FieldNameExtractor fieldNameExtractor,
FieldLocator.Factory fieldLocatorFactory) { FieldLocator.Factory fieldLocatorFactory) {
super(assigner, considerRuntimeType); super(assigner, dynamicallyTyped);
this.fieldNameExtractor = fieldNameExtractor; this.fieldNameExtractor = fieldNameExtractor;
this.fieldLocatorFactory = fieldLocatorFactory; this.fieldLocatorFactory = fieldLocatorFactory;
} }


@Override @Override
public AssignerConfigurable in(FieldLocator.Factory fieldLocatorFactory) { public AssignerConfigurable in(FieldLocator.Factory fieldLocatorFactory) {
return new ForUnnamedField(assigner, considerRuntimeType, fieldNameExtractor, nonNull(fieldLocatorFactory)); return new ForUnnamedField(assigner, dynamicallyTyped, fieldNameExtractor, nonNull(fieldLocatorFactory));
} }


@Override @Override
Expand All @@ -612,8 +612,8 @@ public AssignerConfigurable in(TypeDescription typeDescription) {
} }


@Override @Override
public Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType) { public Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped) {
return new ForUnnamedField(nonNull(assigner), considerRuntimeType, fieldNameExtractor, fieldLocatorFactory); return new ForUnnamedField(nonNull(assigner), dynamicallyTyped, fieldNameExtractor, fieldLocatorFactory);
} }


@Override @Override
Expand Down Expand Up @@ -648,7 +648,7 @@ public int hashCode() {
public String toString() { public String toString() {
return "FieldAccessor.ForUnnamedField{" + return "FieldAccessor.ForUnnamedField{" +
"assigner=" + assigner + "assigner=" + assigner +
"considerRuntimeType=" + considerRuntimeType + "dynamicallyTyped=" + dynamicallyTyped +
"fieldLocatorFactory=" + fieldLocatorFactory + "fieldLocatorFactory=" + fieldLocatorFactory +
"fieldNameExtractor=" + fieldNameExtractor + "fieldNameExtractor=" + fieldNameExtractor +
'}'; '}';
Expand Down Expand Up @@ -679,13 +679,13 @@ protected static class ForNamedField extends FieldAccessor implements FieldDefin
* Creates a field accessor instrumentation for a field of a given name. * Creates a field accessor instrumentation for a field of a given name.
* *
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
* @param fieldName The name of the field. * @param fieldName The name of the field.
*/ */
protected ForNamedField(Assigner assigner, protected ForNamedField(Assigner assigner,
boolean considerRuntimeType, boolean dynamicallyTyped,
String fieldName) { String fieldName) {
super(assigner, considerRuntimeType); super(assigner, dynamicallyTyped);
this.fieldName = fieldName; this.fieldName = fieldName;
preparationHandler = PreparationHandler.NoOp.INSTANCE; preparationHandler = PreparationHandler.NoOp.INSTANCE;
fieldLocatorFactory = FieldLocator.ForInstrumentedTypeHierarchy.Factory.INSTANCE; fieldLocatorFactory = FieldLocator.ForInstrumentedTypeHierarchy.Factory.INSTANCE;
Expand All @@ -699,14 +699,14 @@ protected ForNamedField(Assigner assigner,
* @param fieldLocatorFactory A factory that will produce a field locator that will be used to find locate * @param fieldLocatorFactory A factory that will produce a field locator that will be used to find locate
* a field to be accessed. * a field to be accessed.
* @param assigner The assigner to use. * @param assigner The assigner to use.
* @param considerRuntimeType {@code true} if a field value's runtime type should be considered. * @param dynamicallyTyped {@code true} if a field value's runtime type should be considered.
*/ */
private ForNamedField(Assigner assigner, private ForNamedField(Assigner assigner,
boolean considerRuntimeType, boolean dynamicallyTyped,
String fieldName, String fieldName,
PreparationHandler preparationHandler, PreparationHandler preparationHandler,
FieldLocator.Factory fieldLocatorFactory) { FieldLocator.Factory fieldLocatorFactory) {
super(assigner, considerRuntimeType); super(assigner, dynamicallyTyped);
this.fieldName = fieldName; this.fieldName = fieldName;
this.preparationHandler = preparationHandler; this.preparationHandler = preparationHandler;
this.fieldLocatorFactory = fieldLocatorFactory; this.fieldLocatorFactory = fieldLocatorFactory;
Expand All @@ -720,7 +720,7 @@ public AssignerConfigurable defineAs(Class<?> type, ModifierContributor.ForField
@Override @Override
public AssignerConfigurable defineAs(TypeDescription typeDescription, ModifierContributor.ForField... modifier) { public AssignerConfigurable defineAs(TypeDescription typeDescription, ModifierContributor.ForField... modifier) {
return new ForNamedField(assigner, return new ForNamedField(assigner,
considerRuntimeType, dynamicallyTyped,
fieldName, fieldName,
new PreparationHandler.FieldDefiner(fieldName, nonVoid(typeDescription), nonNull(modifier)), new PreparationHandler.FieldDefiner(fieldName, nonVoid(typeDescription), nonNull(modifier)),
FieldLocator.ForInstrumentedType.INSTANCE); FieldLocator.ForInstrumentedType.INSTANCE);
Expand All @@ -729,7 +729,7 @@ public AssignerConfigurable defineAs(TypeDescription typeDescription, ModifierCo
@Override @Override
public AssignerConfigurable in(FieldLocator.Factory fieldLocatorFactory) { public AssignerConfigurable in(FieldLocator.Factory fieldLocatorFactory) {
return new ForNamedField(assigner, return new ForNamedField(assigner,
considerRuntimeType, dynamicallyTyped,
fieldName, fieldName,
preparationHandler, preparationHandler,
nonNull(fieldLocatorFactory)); nonNull(fieldLocatorFactory));
Expand All @@ -748,9 +748,9 @@ public AssignerConfigurable in(TypeDescription typeDescription) {
} }


@Override @Override
public Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType) { public Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped) {
return new ForNamedField(nonNull(assigner), return new ForNamedField(nonNull(assigner),
considerRuntimeType, dynamicallyTyped,
fieldName, fieldName,
preparationHandler, preparationHandler,
fieldLocatorFactory); fieldLocatorFactory);
Expand Down Expand Up @@ -795,7 +795,7 @@ public int hashCode() {
public String toString() { public String toString() {
return "FieldAccessor.ForNamedField{" + return "FieldAccessor.ForNamedField{" +
"assigner=" + assigner + "assigner=" + assigner +
"considerRuntimeType=" + considerRuntimeType + "dynamicallyTyped=" + dynamicallyTyped +
"fieldName='" + fieldName + '\'' + "fieldName='" + fieldName + '\'' +
", preparationHandler=" + preparationHandler + ", preparationHandler=" + preparationHandler +
", fieldLocatorFactory=" + fieldLocatorFactory + ", fieldLocatorFactory=" + fieldLocatorFactory +
Expand Down
Expand Up @@ -35,18 +35,18 @@ public abstract class FixedValue implements Instrumentation {
/** /**
* Determines if the runtime type of a fixed value should be considered for the assignment to a return type. * Determines if the runtime type of a fixed value should be considered for the assignment to a return type.
*/ */
protected final boolean considerRuntimeType; protected final boolean dynamicallyTyped;


/** /**
* Creates a new fixed value instrumentation. * Creates a new fixed value instrumentation.
* *
* @param assigner The assigner to use for assigning the fixed value to the return type of the instrumented value. * @param assigner The assigner to use for assigning the fixed value to the return type of the instrumented value.
* @param considerRuntimeType If {@code true}, the runtime type of the given value will be considered for assigning * @param dynamicallyTyped If {@code true}, the runtime type of the given value will be considered for assigning
* the return type. * the return type.
*/ */
protected FixedValue(Assigner assigner, boolean considerRuntimeType) { protected FixedValue(Assigner assigner, boolean dynamicallyTyped) {
this.assigner = assigner; this.assigner = assigner;
this.considerRuntimeType = considerRuntimeType; this.dynamicallyTyped = dynamicallyTyped;
} }


/** /**
Expand Down Expand Up @@ -216,7 +216,8 @@ protected ByteCodeAppender.Size apply(MethodVisitor methodVisitor,
MethodDescription instrumentedMethod, MethodDescription instrumentedMethod,
TypeDescription fixedValueType, TypeDescription fixedValueType,
StackManipulation valueLoadingInstruction) { StackManipulation valueLoadingInstruction) {
StackManipulation assignment = assigner.assign(fixedValueType, instrumentedMethod.getReturnType(), considerRuntimeType); StackManipulation assignment = assigner.assign(fixedValueType, instrumentedMethod.getReturnType(),
dynamicallyTyped);
if (!assignment.isValid()) { if (!assignment.isValid()) {
throw new IllegalArgumentException("Cannot return value of type " + fixedValueType + " for " + instrumentedMethod); throw new IllegalArgumentException("Cannot return value of type " + fixedValueType + " for " + instrumentedMethod);
} }
Expand All @@ -231,13 +232,13 @@ protected ByteCodeAppender.Size apply(MethodVisitor methodVisitor,
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return this == other || !(other == null || getClass() != other.getClass()) return this == other || !(other == null || getClass() != other.getClass())
&& considerRuntimeType == ((FixedValue) other).considerRuntimeType && dynamicallyTyped == ((FixedValue) other).dynamicallyTyped
&& assigner.equals(((FixedValue) other).assigner); && assigner.equals(((FixedValue) other).assigner);
} }


@Override @Override
public int hashCode() { public int hashCode() {
return 31 * assigner.hashCode() + (considerRuntimeType ? 1 : 0); return 31 * assigner.hashCode() + (dynamicallyTyped ? 1 : 0);
} }


/** /**
Expand All @@ -251,11 +252,11 @@ public static interface AssignerConfigurable extends Instrumentation {
* *
* @param assigner The assigner to use for assigning the fixed value to the return type of the * @param assigner The assigner to use for assigning the fixed value to the return type of the
* instrumented value. * instrumented value.
* @param considerRuntimeType If {@code true}, the runtime type of the given value will be considered for * @param dynamicallyTyped If {@code true}, the runtime type of the given value will be considered for
* assigning the return type. * assigning the return type.
* @return A fixed value instrumentation that makes use of the given assigner. * @return A fixed value instrumentation that makes use of the given assigner.
*/ */
Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType); Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped);
} }


/** /**
Expand All @@ -282,21 +283,21 @@ protected static class ForPoolValue extends FixedValue implements AssignerConfig
* @param loadedType A type description representing the loaded type. * @param loadedType A type description representing the loaded type.
* @param assigner The assigner to use for assigning the fixed value to the return type of the * @param assigner The assigner to use for assigning the fixed value to the return type of the
* instrumented value. * instrumented value.
* @param considerRuntimeType If {@code true}, the runtime type of the given value will be considered for * @param dynamicallyTyped If {@code true}, the runtime type of the given value will be considered for
* assigning the return type. * assigning the return type.
*/ */
private ForPoolValue(StackManipulation valueLoadInstruction, private ForPoolValue(StackManipulation valueLoadInstruction,
TypeDescription loadedType, TypeDescription loadedType,
Assigner assigner, Assigner assigner,
boolean considerRuntimeType) { boolean dynamicallyTyped) {
super(assigner, considerRuntimeType); super(assigner, dynamicallyTyped);
this.valueLoadInstruction = valueLoadInstruction; this.valueLoadInstruction = valueLoadInstruction;
this.loadedType = loadedType; this.loadedType = loadedType;
} }


@Override @Override
public Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType) { public Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped) {
return new ForPoolValue(valueLoadInstruction, loadedType, nonNull(assigner), considerRuntimeType); return new ForPoolValue(valueLoadInstruction, loadedType, nonNull(assigner), dynamicallyTyped);
} }


@Override @Override
Expand Down Expand Up @@ -341,7 +342,7 @@ public String toString() {
"valueLoadInstruction=" + valueLoadInstruction + "valueLoadInstruction=" + valueLoadInstruction +
", loadedType=" + loadedType + ", loadedType=" + loadedType +
", assigner=" + assigner + ", assigner=" + assigner +
", considerRuntimeType=" + considerRuntimeType + ", dynamicallyTyped=" + dynamicallyTyped +
'}'; '}';
} }
} }
Expand Down Expand Up @@ -378,11 +379,11 @@ protected static class ForStaticField extends FixedValue implements AssignerConf
* @param fixedValue The fixed value to be returned. * @param fixedValue The fixed value to be returned.
* @param assigner The assigner to use for assigning the fixed value to the return type of the * @param assigner The assigner to use for assigning the fixed value to the return type of the
* instrumented value. * instrumented value.
* @param considerRuntimeType If {@code true}, the runtime type of the given value will be considered for * @param dynamicallyTyped If {@code true}, the runtime type of the given value will be considered for
* assigning the return type. * assigning the return type.
*/ */
protected ForStaticField(Object fixedValue, Assigner assigner, boolean considerRuntimeType) { protected ForStaticField(Object fixedValue, Assigner assigner, boolean dynamicallyTyped) {
this(String.format("%s$%d", PREFIX, Math.abs(fixedValue.hashCode())), fixedValue, assigner, considerRuntimeType); this(String.format("%s$%d", PREFIX, Math.abs(fixedValue.hashCode())), fixedValue, assigner, dynamicallyTyped);
} }


/** /**
Expand All @@ -392,19 +393,19 @@ protected ForStaticField(Object fixedValue, Assigner assigner, boolean considerR
* @param fixedValue The fixed value to be returned. * @param fixedValue The fixed value to be returned.
* @param assigner The assigner to use for assigning the fixed value to the return type of the * @param assigner The assigner to use for assigning the fixed value to the return type of the
* instrumented value. * instrumented value.
* @param considerRuntimeType If {@code true}, the runtime type of the given value will be considered for * @param dynamicallyTyped If {@code true}, the runtime type of the given value will be considered for
* assigning the return type. * assigning the return type.
*/ */
protected ForStaticField(String fieldName, Object fixedValue, Assigner assigner, boolean considerRuntimeType) { protected ForStaticField(String fieldName, Object fixedValue, Assigner assigner, boolean dynamicallyTyped) {
super(assigner, considerRuntimeType); super(assigner, dynamicallyTyped);
this.fieldName = fieldName; this.fieldName = fieldName;
this.fixedValue = fixedValue; this.fixedValue = fixedValue;
fieldType = new TypeDescription.ForLoadedType(fixedValue.getClass()); fieldType = new TypeDescription.ForLoadedType(fixedValue.getClass());
} }


@Override @Override
public Instrumentation withAssigner(Assigner assigner, boolean considerRuntimeType) { public Instrumentation withAssigner(Assigner assigner, boolean dynamicallyTyped) {
return new ForStaticField(fieldName, fixedValue, nonNull(assigner), considerRuntimeType); return new ForStaticField(fieldName, fixedValue, nonNull(assigner), dynamicallyTyped);
} }


@Override @Override
Expand Down Expand Up @@ -439,7 +440,7 @@ public String toString() {
", fieldType=" + fieldType + ", fieldType=" + fieldType +
", fixedValue=" + fixedValue + ", fixedValue=" + fixedValue +
", assigner=" + assigner + ", assigner=" + assigner +
", considerRuntimeType=" + considerRuntimeType + ", dynamicallyTyped=" + dynamicallyTyped +
'}'; '}';
} }


Expand Down

0 comments on commit 2736224

Please sign in to comment.