Skip to content

Commit db80456

Browse files
committed
Add a method to replace a value with a constant directly.
1 parent cb8a9be commit db80456

File tree

2 files changed

+103
-7
lines changed

2 files changed

+103
-7
lines changed

byte-buddy-dep/src/main/java/net/bytebuddy/asm/MemberSubstitution.java

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,49 @@ public MemberSubstitution stub() {
295295
return replaceWith(Substitution.Stubbing.INSTANCE);
296296
}
297297

298+
/**
299+
* Replaces any interaction with a matched byte code element with the provided compile-time constant.
300+
*
301+
* @param value The compile-time constant to set.
302+
* @return A member substitution that replaces any interaction with the supplied compile-time constant.
303+
*/
304+
public MemberSubstitution replaceWithConstant(Object value) {
305+
if (value instanceof JavaConstant) {
306+
return replaceWith(new Substitution.ForValue(new JavaConstantValue((JavaConstant) value), ((JavaConstant) value).getTypeDescription().asGenericType()));
307+
} else if (value instanceof TypeDescription) {
308+
return replaceWith(new Substitution.ForValue(ClassConstant.of((TypeDescription) value), TypeDefinition.Sort.describe(Class.class)));
309+
} else {
310+
Class<?> type = value.getClass();
311+
if (type == String.class) {
312+
return replaceWith(new Substitution.ForValue(new TextConstant((String) value), TypeDefinition.Sort.describe(String.class)));
313+
} else if (type == Class.class) {
314+
return replaceWith(new Substitution.ForValue(ClassConstant.of(TypeDescription.ForLoadedType.of((Class<?>) value)), TypeDefinition.Sort.describe(Class.class)));
315+
} else if (type == Boolean.class) {
316+
return replaceWith(new Substitution.ForValue(IntegerConstant.forValue((Boolean) value), TypeDefinition.Sort.describe(boolean.class)));
317+
} else if (type == Byte.class) {
318+
return replaceWith(new Substitution.ForValue(IntegerConstant.forValue((Byte) value), TypeDefinition.Sort.describe(byte.class)));
319+
} else if (type == Short.class) {
320+
return replaceWith(new Substitution.ForValue(IntegerConstant.forValue((Short) value), TypeDefinition.Sort.describe(short.class)));
321+
} else if (type == Character.class) {
322+
return replaceWith(new Substitution.ForValue(IntegerConstant.forValue((Character) value), TypeDefinition.Sort.describe(char.class)));
323+
} else if (type == Integer.class) {
324+
return replaceWith(new Substitution.ForValue(IntegerConstant.forValue((Integer) value), TypeDefinition.Sort.describe(int.class)));
325+
} else if (type == Long.class) {
326+
return replaceWith(new Substitution.ForValue(LongConstant.forValue((Long) value), TypeDefinition.Sort.describe(long.class)));
327+
} else if (type == Float.class) {
328+
return replaceWith(new Substitution.ForValue(FloatConstant.forValue((Float) value), TypeDefinition.Sort.describe(float.class)));
329+
} else if (type == Double.class) {
330+
return replaceWith(new Substitution.ForValue(DoubleConstant.forValue((Double) value), TypeDefinition.Sort.describe(double.class)));
331+
} else if (JavaType.METHOD_HANDLE.getTypeStub().isAssignableFrom(type)) {
332+
return replaceWith(new Substitution.ForValue(new JavaConstantValue(JavaConstant.MethodHandle.ofLoaded(value)), TypeDefinition.Sort.describe(type)));
333+
} else if (JavaType.METHOD_TYPE.getTypeStub().represents(type)) {
334+
return replaceWith(new Substitution.ForValue(new JavaConstantValue(JavaConstant.MethodType.ofLoaded(value)), TypeDefinition.Sort.describe(type)));
335+
} else {
336+
throw new IllegalArgumentException("Not a constant value: " + value);
337+
}
338+
}
339+
}
340+
298341
/**
299342
* <p>
300343
* Replaces any interaction with a matched byte code element by an interaction with the specified field. If a field
@@ -869,6 +912,43 @@ public StackManipulation resolve(TypeDescription targetType,
869912
}
870913
}
871914

915+
class ForValue implements Substitution, Factory {
916+
917+
private final StackManipulation stackManipulation;
918+
919+
private final TypeDescription.Generic typeDescription;
920+
921+
public ForValue(StackManipulation stackManipulation, TypeDescription.Generic typeDescription) {
922+
this.stackManipulation = stackManipulation;
923+
this.typeDescription = typeDescription;
924+
}
925+
926+
/**
927+
* {@inheritDoc}
928+
*/
929+
public Substitution make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
930+
return this;
931+
}
932+
933+
/**
934+
* {@inheritDoc}
935+
*/
936+
public StackManipulation resolve(TypeDescription targetType,
937+
ByteCodeElement target,
938+
TypeList.Generic parameters,
939+
TypeDescription.Generic result,
940+
int freeOffset) {
941+
List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(parameters.size());
942+
for (int index = parameters.size() - 1; index >= 0; index--) {
943+
stackManipulations.add(Removal.of(parameters.get(index)));
944+
}
945+
if (!typeDescription.asErasure().isAssignableTo(result.asErasure())) {
946+
throw new IllegalStateException("Cannot assign " + typeDescription + " to " + result);
947+
}
948+
return new StackManipulation.Compound(CompoundList.of(stackManipulations, stackManipulation));
949+
}
950+
}
951+
872952
/**
873953
* A substitution with a field access.
874954
*/
@@ -1624,7 +1704,7 @@ public Resolution resolve(TypeDescription targetType,
16241704
int freeOffset) {
16251705
return targetType.represents(void.class)
16261706
? this
1627-
: new Simple(new StackManipulation.Compound(Removal.of(targetType), stackManipulation), resultType);
1707+
: new Simple(new StackManipulation.Compound(Removal.of(current), stackManipulation), resultType);
16281708
}
16291709

16301710
/**
@@ -1832,9 +1912,9 @@ class ForArgumentLoading implements Step {
18321912
/**
18331913
* Creates an argument loading step.
18341914
*
1835-
* @param index The index of the argument to load.
1836-
* @param assigner The assigner to use for assigning the argument.
1837-
* @param typing The typing to use for the argument assignment.
1915+
* @param index The index of the argument to load.
1916+
* @param assigner The assigner to use for assigning the argument.
1917+
* @param typing The typing to use for the argument assignment.
18381918
*/
18391919
protected ForArgumentLoading(int index,
18401920
Assigner assigner,

byte-buddy-dep/src/test/java/net/bytebuddy/asm/MemberSubstitutionTypeTest.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,35 @@ public static Collection<Object[]> data() {
4545
}
4646

4747
@Test
48-
public void testSubstitutionChainSimple() throws Exception {
48+
public void testSubstitutionReplacement() throws Exception {
4949
Class<?> type = new ByteBuddy()
5050
.redefine(this.type)
51-
.visit(MemberSubstitution.strict().field(named(FOO)).replaceWithChain(MemberSubstitution.Substitution.Chain.Step.Simple.of(value)).on(named(RUN)))
51+
.visit(MemberSubstitution.strict().field(named(FOO)).replaceWithConstant(replacement).on(named(RUN)))
5252
.make()
5353
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
5454
.getLoaded();
5555
Object instance = type.getDeclaredConstructor().newInstance();
5656
assertThat(type.getDeclaredField(FOO).get(instance), is(value));
5757
assertThat(type.getDeclaredField(BAR).get(instance), is(value));
5858
assertThat(type.getDeclaredMethod(RUN).invoke(instance), nullValue(Object.class));
59-
assertThat(type.getDeclaredField(FOO).get(instance), is(replacement));
59+
assertThat(type.getDeclaredField(FOO).get(instance), is(value));
60+
assertThat(type.getDeclaredField(BAR).get(instance), is(replacement));
61+
}
62+
63+
@Test
64+
public void testSubstitutionChainSimple() throws Exception {
65+
Class<?> type = new ByteBuddy()
66+
.redefine(this.type)
67+
.visit(MemberSubstitution.strict().field(named(FOO)).replaceWithChain(MemberSubstitution.Substitution.Chain.Step.Simple.of(replacement)).on(named(RUN)))
68+
.make()
69+
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
70+
.getLoaded();
71+
Object instance = type.getDeclaredConstructor().newInstance();
72+
assertThat(type.getDeclaredField(FOO).get(instance), is(value));
6073
assertThat(type.getDeclaredField(BAR).get(instance), is(value));
74+
assertThat(type.getDeclaredMethod(RUN).invoke(instance), nullValue(Object.class));
75+
assertThat(type.getDeclaredField(FOO).get(instance), is(value));
76+
assertThat(type.getDeclaredField(BAR).get(instance), is(replacement));
6177
}
6278

6379
@Test

0 commit comments

Comments
 (0)