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/AutoproxyREADME
1. 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.
<details> <summary>UML PROXY PATTERN:</summary> </details>- 1. AutoProxy
- 2. Why should I use it?
- 3. Concepts
- 4. Setup Guide
- 5. Advanced Usage (Patterns)
- 6. Troubles
- 7. Roadmap
- 8. License
2. Why should I use it?
2.1. Use Cases
- 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)
- inject side-effects on top of existing implementation. Example: log all the calls to proxy, control sequence and performance;
- Lazy initialization, record all calls and playback them on instance that reach a specific state;
- Mutability injection into AutoValue Builder (complex data migration from one AutoValue instance to another). AutoValue classes as DB with automatic Primary Key auto-increment;
- Mocks vs Fakes. Generate a fake implementation by annotating primary interface/abstract class
- 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.
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


