# Invocation replacement

And now, something completely different:) **Proxetta** provides proxy mechanism that may **replace** almost any method invocation, including object creation (i.e. constructors) with custom method call. For example, it is possible to replace invocation of some interface methods with some custom implementation. Or, ahead to more loose-coupled code, it is possible to replace object creation with a factory method that returns wired and populated objects.

### Usage

Usage is identical to how **Proxetta** works with dynamic proxies - we just need to provide different types of aspects: `InvokeAspect`. `InvokeAspect` defines the **pointcut**, i.e. the method invocation that should be replaced and the **advice**, i.e. destination method that should be invoked instead.

Here is an example of proxy creation:

```java
Proxetta proxetta = Proxy.invokeProxetta().withAspect(
    invokeInfo -> {
        if (invokeInfo.getMethodName().equals("foo")) {
            return InvokeReplacer.with(Replacer.class, "bar");
        }
        return null;
    }
};
```

Invoke aspect is set here on all invocations of method named `foo()`. Invocations will be replaced with the static method `Replacer.bar()`. Now, let's apply the proxy:

```java
One one = proxetta.proxy().setTarget(One.class).newInstance();
```

The instance of `One` is now proxified. If class `One` looks like this:

```java
public class One {
    public void example1() {
        Two two = new Two();
        int i = two.foo("one");
        System.out.print(i);
    }
}
```

it will be modified: `foo` method call will be replaced and generated bytecode will look like this:

```java
public void example1() {
    Two two = new Two();
    int i = Replacer.bar(two);
    System.out.print(i);
}
```

Nice!

#### Another example

Let's replace all calls to `System.currentTimeMillis()` with custom method. For the purpose of this example, let's say that we have a class like this:

```java
public class TimeClass {

    public long time() {
        return System.currentTimeMillis();
    }
}
```

Ok, here is how to build a proxy class:

```java
TimeClass timeClass =
(TimeClass) InvokeProxetta.withAspects(new InvokeAspect() {
    @Override
    public boolean apply(MethodInfo methodInfo) {
        return methodInfo.isTopLevelMethod();
    }

    @Override
    public InvokeReplacer pointcut(InvokeInfo invokeInfo) {
        if (
                invokeInfo.getClassName().equals("java.lang.System") &&
                invokeInfo.getMethodName().equals("currentTimeMillis")
            ) {
            return InvokeReplacer.with(MySystem.class, "currentTimeMillis");
        }
        return null;
    }
}).builder(TimeClass.class).newInstance();
```

What we have here? We created `InvokeAspect` that will be applied on all top-level methods of the target class (`TimeClass` in this example); and in the pointcut we defined *what* invocation to replace and the *replacement* call. Now, the code will call `MySystem.currentTimeMillis` instead of `System`'s' method in all top-level methods of `TimeClass`.

Remember:

Methods `apply` and `builder` define **where** to apply the proxy (the target), `pointcut` defines **what** invocation to replace in target and the **replacement** call. {: .attn}

Simple, right :)

### InvokeInfo and InvokeReplacer

`InvokeInfo` contains a lot of information about the methods being invoked. It is used to determine if some method call should be replaced or not. Using `InvokeInfo` we can get class name, method signatures, arguments etc. of the invoked methods; so we can decide if some invocation is a target one, one that should be replaced.

`InvokeReplacer` holds information about the replacement method - the one that will be invoked *instead* of the target method. Replacement method is defined as a class name and a method name.

Replacement methods must be static! {: .attn}

Moreover, using `InvokeReplacer` we can instruct to pass some additional arguments to replaced method, depending of the target method's signature.

#### Dynamic replacements

Because the replacement method is defined as a string, we can build them dynamically, as in the following example:

```java
invokeInfo -> {
    return InvokeReplacer.with(Replacer.class,
        invokeInfo.getMethodName() + invokeInfo.getArgumentsCount());
}
```

Here all method invocation are replaced with `Replacer` methods which names contains original method name and number of arguments. For example, call to `foo("xxx")` is replaced with `Replacer.foo1("xxx"`).

### Replacements

There are several different types of invocation in Java, so there are as many different replacement points in `Proxetta`. Each replacement method must take the same number of arguments and must return the same type of result. When replaced method is an instance method, there will be an additional argument holding the reference to the instance.

#### Virtual invocation

This is a simple method call on an instance, as in above example. Replacement method receives following arguments:

* reference to instance of method owner (in the above example its `two`)
* all arguments of the replaced method

#### Static methods

Static methods are replaced without any additional arguments.

#### Interface methods

Similar to virtual methods, interface method calls are replaced with method call that receives an additional argument, that is interface implementation.

#### Constructors

Constructors' replacement methods doesn't receive any additional argument and must return the created instance. Important: due to VM bytecode, when replacing constructors, there must be a replacement method for each present constructor!

Replacing constructors creation with method invocation might be a powerful feature. Let's take an example:

```java
public class One {
    public void example() {
        Two two = new Two();
        two.hello();
    }
}
public class Two() {
    public String value;
    public void hello() {
        System.out.println(value);
    }
}
```

If we call method `One#example()` it would, obviously, print "`null`". Now, let's replace the constructor call with **Proxetta**:

```java
InvokeProxetta proxetta = Proxy.invokeProxetta.proxy().withAspect(
        invokeInfo -> {
            if (invokeInfo.getMethodName().equals("<init>")) {
                return InvokeReplacer.with(Replacer.class,
                    "new" + invokeInfo.getClassShortName());
            } else {
                return null;
            }
        }
    );
```

Now we are replacing **all** constructors with `Replacer#new${ClassName}` methods. For example:

```java
public class Replacer {
    public static Two newTwo() {
        Two two = new Two();
        two.value = "hello";
        return two;
    }
}
```

If we run proxified class `One`, this time we will have the result `hello`. And we didn't touch the source of `One`!

### Additional arguments

The replacement method receives all arguments as a replaced method, plus the reference to target instance if available. However, we can instruct `InvokeReplacer` to provide more arguments in replacement methods. Here are the available additional arguments:

* owner name
* method name
* method signature
* reference to this
* target class

All additional arguments are placed at the end, after existing method arguments.

### Under the hood

How does the **Proxetta** do all this? It creates an identical subclass as a target, but with replaced method invocations.

Because of the nature of subclass, there are some VM limitations that we have to be aware of.

#### Don't call super()

Because `super.super` is not provided by VM.

#### Constructors are executed twice

Since subclass copies constructors too, they will be executed as well as the target class constructors. So all initialization will be executed twice, once for proxified class, then for the target class. Therefore, do not put heavy-duty initialization in the constructor.
