Skip to content

CRedirect

Lenni0451 edited this page Mar 21, 2024 · 2 revisions

The CRedirect annotation can be used to redirect method calls, field accesses and new object creations to a method.

Method signature

The method signature of the transformer method depends on the redirect target.
When injecting into a static method, the transformer method also needs to be static and vice versa.

Redirecting method calls

For redirecting method calls, the transformer method needs to have the same parameters and return type as the target method call with the addition of the target instance (if the target method is not static) as the first parameter.

//Injecting into a static method, the target method is not static
@CRedirect(target = @CTarget(value = "INVOKE", target = "LOwner;method(ILjava/lang/String;)I"), ...)
public static int transform(final Owner instance, final int arg1, final String arg2)

//Injecting into a non-static method, the target method is static
@CRedirect(target = @CTarget(value = "INVOKE", target = "LOwner;method(ILjava/lang/String;)I"), ...)
public int transform(final int arg1, final String arg2)

Redirecting field accesses

Field getter

For redirecting field getters, the transformer method needs to have the field owner as the first parameter (if the field is not static) and the field type as the return type.

//Injecting into a static method, the target field is not static
@CRedirect(target = @CTarget(value = "GETFIELD", target = "LOwner;field:I"), ...)
public static int transform(final Owner instance)

//Injecting into a non-static method, the target field is static
@CRedirect(target = @CTarget(value = "GETFIELD", target = "LOwner;field:I"), ...)
public int transform()

Field setter

For redirecting field setters, the transformer method needs to have the field owner as the first parameter (if the field is not static), the field type as the second parameter and the return type as void.

//Injecting into a static method, the target field is not static
@CRedirect(target = @CTarget(value = "PUTFIELD", target = "LOwner;field:I"), ...)
public static void transform(final Owner instance, final int value)

//Injecting into a non-static method, the target field is static
@CRedirect(target = @CTarget(value = "PUTFIELD", target = "LOwner;field:I"), ...)
public void transform(final int value)

Redirecting new object creations

For redirecting new object creations, the transformer method needs to have the same parameters as the target constructor and the return type as the instantiated class.

//Injecting into a static method
@CRedirect(target = @CTarget(value = "NEW", target = "Owner"), ...)
public static Owner transform(final int arg1, final String arg2)

//Injecting into a non-static method
@CRedirect(target = @CTarget(value = "NEW", target = "Owner"), ...)
public Owner transform(final int arg1, final String arg2)

Targets

The target field of the CRedirect annotation specifies the redirected method/field/constructor.
Check out the CTarget page for more information about the different targets.
Also, check out CSlice for more information about how slices work.

Targeting multiple methods

The method field can be an array of strings to target multiple methods.
The transformer method needs to be compatible with all targeted methods.

@CRedirect(method = {"method1", "method2"}, ...)
public void transform(final String arg)

Examples

Original method:

public void method() {
    this.test = new Test("This is a test");
    System.out.println(this.test.getMessage());
}

Redirecting method call

Transformer method:

@CRedirect(method = "method", target = @CTarget(value = "INVOKE", target = "Test.getMessage()Ljava/lang/String;"))
public String transform(final Test instance) {
    return "This is a redirected test";
}

Injected code:

public void method() {
    this.test = new Test("This is a test");
    System.out.println(this.transform(this.test));
}

Redirecting field access

Transformer method:

@CRedirect(method = "method", target = @CTarget(value = "PUTFIELD", target = "Example.test:LTest;"))
public void putField(final Example instance, final Test value) {
    instance.test = new Test("This is a redirected test 1");
}

@CRedirect(method = "method", target = @CTarget(value = "GETFIELD", target = "java/lang/System.out:Ljava/io/PrintStream;"))
public PrintStream getField() {
    return System.err;
}

Injected code:

public void method() {
    this.putField(this, new Test("This is a test"));
    this.getField().println(this.test.getMessage());
}

Redirecting new object creation

Transformer method:

@CRedirect(method = "method", target = @CTarget(value = "NEW", target = "Test"))
public Test transform(final String message) {
    return new Test(message + " 2");
}

Injected code:

public void method() {
    this.test = this.transform("This is a test");
    System.out.println(this.test.getMessage());
}