Share
Embed
Reflection No Reflection
Talk at DroidCon NY // Devoxx BE
2015
Annotation Processing, Reflection, DI, performances, Guice, RoboGuice
stephanenicolas
August 27, 2015
Transcript
41 slides
-
Hey! My name is Stéphane Nicolas. Senior Android Dev @
Groupon ~20 years of Java coding OSS: RoboSpice, RoboGuice, BoundBox, Injects, Dart, … snicolas stephanenicolas +stephane nicolas -
THE TALK • Motivations • Reflection • Alternatives to reflection
• RNЯ : reflection no reflection • Conclusion • Strongly recommend knowledge of: • DI & bindings (ButterKnife, Dart, etc.) • Annotation processing -
ROBOGUICE • —> But slow • Feature Rich • Easy
to configure, and use • No manual graph definition -
But still, 35% improvement is not enough compared to Dagger
1. PERFORMANCES OF DI FRAMEWORK (all figures in ms / GenyMotion) -
WHAT’S REFLECTION ? Simple and intuitive Close to the way
devs talk about OO programs -
Java Source Byte Code App JVM Compiler Reflection ALTERNATIVES TO
REFLECTION Annotation Processing ByteCode Weaving AST Manipulations -
BYTECODE WEAVING On Android : static byte code weaving
performed right after compilation. We got a full stack : the INJECTS projects github.com/stephanenicolas/injects -
๏ Complex libs ๏ Non standard builds —> High
Maintenance ๏ Only jar & class files, not dex ๏ Jack n’Jill ? —> No one knows about Jayce ๏ Modifications are invisible BYTECODE WEAVING ✓ Simple to use ✓ No boiler plate code ✓ As easy as a gradle plugin ✓ Extremely powerful ✓ ‘de facto standard’ API : Javassist. -
AST MANIPULATION Abstract Syntax Trees (AST) : data structures to
represent Java statements, they are used internally by Java compilers. Lombok for Java : projectlombok.org Hrisey for Android : github.com/mg6maciej/hrisey -
๏ Harder than byte code. ๏ Non standard (Android could
focus on Javac) ๏ Jack n’Jill ? —> No one knows about Jayce ๏ Modifications are invisible ✓ Simple to use ✓ No boiler plate code ✓ As easy as a gradle plugin ✓ Extremely powerful AST MANIPULATION -
ANNOTATION PROCESSING Annotation processing allows to generate new code. Some
boiler plate is needed to invoke it. Here, ButterKnife generates code to bind resources and views to fields of an Activity. -
๏ API is difficult ๏ Impossible to modify code. Only
new code can be generated ๏ Every lib based on reflection has to be rewritten ๏ Needs boiler plate to invoke generated code ✓ Simple to use ✓ Java Standard ✓ Relatively powerful ANNOTATION PROCESSING -
In DI & Binding libs generated code is used to
manipulate non private members : • access fields • call methods • call constructors GENERATED CODE —> Like reflection ! -
1) Make it easy to adapt reflection based Java
libs to Android. 2) Get the best of reflection (ease) and annotation processing (speed) 3) Hide generated code RNЯ objectives -
RNЯ: 3 steps 1. Define RNЯ classes: 100 % compatible
with reflection & fill these data structures during annotation processing time . 2. Generate code so that RNЯ becomes available at runtime. 3. Generate code that allows modification of members (access fields, invoke methods and constructors). -
Step 1 : Annotation processing time RNЯ classes Annotation Processing
Compiler Annotation Processor using reflection Generated Java Source -
Step 1 : Results After this step, Annotation Processor can
use the reflection API. We manipulate fields, methods, constructors & classes… before they are compiled ! Unification of Annotation Processing and Reflection API By itself it is an important theoretical achievement in Java. -
Step 2 : RNЯ accessible at runtime Generate code to
fill RNЯ classes Annotation Processing Compiler App RNЯ Reflection -
RNЯ classes • They are 100 % compatible with the
reflection API classes • RNЯ classes are filled during annotation processing • RNЯ classes are generated to become accessible at runtime via Class.forName(‘’test.Foo‘’) -
Step 2 : Results RNЯ reflection classes : • accessible
to libs/apps at runtime • provide read-only access to reflection information • are faster than reflection on Android. But they are read-only, unlike native reflection. -
Step 3 : Write access Generate code to fill
RNЯ classes Annotation Processing Compiler App RNЯ Reflection Class Reflectors -
Step 3 : Results Step 3 extends step 2. Now,
RNЯ reflection classes : • accessible to libs/apps at runtime • provide read/write access to reflection information • are faster than reflection on Android. (Oh, Btw, there is a little detail that we gently omitted : annotation implementations…And we are proud to have succeeded in doing it.) -
RNЯ works, what next ? The general context of research
on RNЯ was improving DI speed. so let’s fork Guice ! It should be as simple as replacing native Reflection with RNЯ reflection. -
RNЯ Guice Guice RNЯ Guice scan classes members Processing
access field invoke methods create instances -
RNЯ Guice : Why it failed • Guice uses a
lot of reflection, many if not all features of reflection —>The fork introduced a high volume of changes… and potential bugs. • Reflection is also linked to the compiler at a very low level via class symbolication / class literals : Reflection Compiler Symbole -
RNЯ Guice fork : take 2 Minimize the amount of
changes in Guice to use RNЯ. Bypass native reflection for members access via reflectors. And only that. Guice RNЯ Guice scan classes members Processing access field invoke methods create instances -
Conclusions RNЯ - Step 1, unifies Annotation Processing and Reflection
at compile-time. RNЯ - Step 2 and Step 3 are a generalization of all the work that has been done on Android related to Annotation Processing to circumvent Reflection. RNЯ demonstrates that this approach is feasible. -
Conclusions RNЯ, got initiated by our desire to achieve a
faster DI for Android. We plan to release soon a new version of Guice / RoboGuice based on the RNЯ reflectors. Not based on the full RNЯ solution. -
Java Source Byte Code App JVM Compiler The solution might
be elsewhere… AOT compilation + JIT reflection code