SkillAgentSearch skills...

Autoproxy

Annotation Processing Library. Generates proxy class on top of interface/abstract class, that allows to intercept calls. Also known as a design pattern: proxy, delegate, interceptor.

Install / Use

/learn @OleksandrKucherenko/Autoproxy

README

1. AutoProxy

Build Status Download

Annotation Processing Library.

Generates proxy class on top of interface/abstract class, that allows to intercept calls.

Also known as a design pattern: proxy, delegate, interceptor.

Diagram

<details> <summary>UML PROXY PATTERN:</summary>

Wikipedia Proxy Pattern

Proxy Pattern

</details>

2. Why should I use it?

2.1. Use Cases

  1. create proxy class that ignore all calls till UI is in a right lifecycle state; Library solves common Mvp View problem: call of view from presenter when view is already detached from Activity. (delayed updated call)
  2. inject side-effects on top of existing implementation. Example: log all the calls to proxy, control sequence and performance;
  3. Lazy initialization, record all calls and playback them on instance that reach a specific state;
  4. Mutability injection into AutoValue Builder (complex data migration from one AutoValue instance to another). AutoValue classes as DB with automatic Primary Key auto-increment;
  5. Mocks vs Fakes. Generate a fake implementation by annotating primary interface/abstract class
  6. Composing Adapter (Frontend) for another API

Library gives a bigger freedom if you think for a second about it:

  • auto-generated Proxy class is simple and does not have any performance impacts. No Reflection. All resolved during the compilation time.
  • Survive ProGuard optimization/obfuscation.
  • used in library approach allows custom generators of code/results. Unknown types is super easy to support.
  • Allows to decouple main application business logic from different side-effects and dependencies (mediator injecting in code)

3. Concepts

3.1. Predicate

Intercept call before the inner instance call. If returns TRUE, than allowed inner instance call. On FALSE developer should decide what to do. Default behavior: throw exception.

  public final Observable<Boolean> dummyCall(final List<String> generic) {
    if (!predicate( "dummyCall", generic )) {
      // @com.olku.annotations.AutoProxy.Yield(adapter=com.olku.generators.RetRxGenerator.class, value="empty")
      return Observable.empty();
    }
    return this.inner.dummyCall(generic);
  }

3.2. AfterCall

From time to time exists situations when we need to intercept and modify results of the inner call.

In that case library provides @AutoProxy.AfterCall annotation, it allows to mark specific method that requires this feature. @AutoProxy(flags = AutoProxy.Flags.AFTER_CALL) enables that for all methods in class/interface.

<details> <summary>AutoValue Builder Sample</summary>

Declaration:

/** Abstract class. */
@AutoValue
public abstract class ParkingArea {

    @AutoValue.Builder
    @AutoProxy
    public static abstract class Builder {
        @AutoProxy.AfterCall
        @NonNull
        public abstract Builder id(final long id);
    }
}

Generated class will contains after that two methods:

public abstract class Proxy_ParkingArea$Builder extends ParkingArea.Builder {
  protected final ParkingArea.Builder inner;

  public abstract boolean predicate(final String methodName, final Object... args);

  public abstract <R> R afterCall(final String methodName, final R result);

  /* ... other methods ... */
}
</details>

Change of internal proxy pattern:

  public final ParkingArea build() {
    if (!predicate( "build" )) {
      throw new UnsupportedOperationException("cannot resolve return type.");
    }

    return afterCall("build", this.inner.build());
  }

4. Setup Guide

You can use it as a submodule or as compiled libs.

4.1. Configure Dependencies

/* include repository */
repositories {
    maven {
        url  "https://dl.bintray.com/kucherenko-alex/android"
    }
}
/* add dependencies */
dependencies{
    /* AutoProxy generator */
    compileOnly 'com.olku:autoproxy-annotations:+'
    compileOnly 'com.olku:autoproxy-rx-annotations:+'
    compileOnly 'com.olku:autoproxy-rx3-generators:+'

    annotationProcessor 'com.olku:autoproxy-rx3-generators:+'
    annotationProcessor 'com.olku:autoproxy-processor:+'
}
<details> <summary>With RxJava v1.xx Support</summary>
/* add dependencies */
dependencies{
    /* AutoProxy generator */
    compileOnly 'com.olku:autoproxy-annotations:+'
    compileOnly 'com.olku:autoproxy-rx-annotations:+'
    compileOnly 'com.olku:autoproxy-rx-generators:+' /* RxJava v1.xx */

    annotationProcessor 'com.olku:autoproxy-rx-generators:+' /* RxJava v1.xx */
    annotationProcessor 'com.olku:autoproxy-processor:+'

}
</details> <details> <summary>With RxJava v2.xx Support</summary>
/* add dependencies */
dependencies{
    /* AutoProxy generator */
    compileOnly 'com.olku:autoproxy-annotations:+'
    compileOnly 'com.olku:autoproxy-rx-annotations:+'
    compileOnly 'com.olku:autoproxy-rx2-generators:+' /* RxJava v2.xx */

    annotationProcessor 'com.olku:autoproxy-rx2-generators:+' /* RxJava v2.xx */
    annotationProcessor 'com.olku:autoproxy-processor:+'
}
</details> <details> <summary>With RxJava v3.xx Support</summary>
/* add dependencies */
dependencies{
    /* AutoProxy generator */
    compileOnly 'com.olku:autoproxy-annotations:+'
    compileOnly 'com.olku:autoproxy-rx-annotations:+'
    compileOnly 'com.olku:autoproxy-rx3-generators:+' /* RxJava v3.xx */

    annotationProcessor 'com.olku:autoproxy-rx3-generators:+' /* RxJava v3.xx */
    annotationProcessor 'com.olku:autoproxy-processor:+'
}
</details> <details> <summary>OR attach as a submodule</summary>

attach repository as a submodule:

# initialize project for submodules usage
git submodule init

# add submodule
git submodule add https://github.com/OleksandrKucherenko/autoproxy.git modules/autoproxy

# update project recursively and pull all submodules
git submodule update --init --recursive

include submodule into project

app/build.gradle:

    /* AutoProxy generator */
    compileOnly project(':modules:autoproxy:autoproxy-annotations')
    compileOnly project(':modules:autoproxy:autoproxy-rx-annotations')
    compileOnly project(':modules:autoproxy:autoproxy-rx-generators') /* RxJava v1.xx */
    compileOnly project(':modules:autoproxy:autoproxy-rx2-generators') /* RxJava v2.xx */

    /* For Java Projects */
    annotationProcessor project(':modules:autoproxy:autoproxy-rx-generators') /* RxJava v1.xx */
    annotationProcessor project(':modules:autoproxy:autoproxy-rx2-generators') /* RxJava v2.xx */
    annotationProcessor project(':modules:autoproxy:autoproxy-processor')

    /* OR for Kotlin Projects */
    kapt project(':modules:autoproxy-rx-generators') /* RxJava v1.xx */
    kapt project(':modules:autoproxy-rx2-generators') /* RxJava v2.xx */
    kapt project(':modules:autoproxy-processor')

settings.gradle:

include ':modules:autoproxy:autoproxy-annotations'
include ':modules:autoproxy:autoproxy-generators'
include ':modules:autoproxy:autoproxy-rx-annotations'
include ':modules:autoproxy:autoproxy-rx-generators'
include ':modules:autoproxy:autoproxy-rx2-generators'
include ':modules:autoproxy:autoproxy-processor'
</details>

4.2. Make Proxy Class Specification

/** Simplest case */
@AutoProxy
public interface MvpView {
  /* ... declare method ... */
}

OR check the bigger example bellow.

<details> <summary>Declarations - Show code</summary>
@AutoProxy(flags = AutoProxy.Flags.ALL)
public interface MvpView {
    /** Returns NULL if predicate returns False. */
    @AutoProxy.Yield(Returns.NULL)
    Observable<Boolean> dummyCall();

    /** Returns Observable.empty() */
    @AutoProxy.Yield(adapter = RetRxGenerator
View on GitHub
GitHub Stars22
CategoryDesign
Updated7mo ago
Forks2

Languages

Java

Security Score

87/100

Audited on Aug 27, 2025

No findings