-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interceptors api #771
Interceptors api #771
Conversation
Codecov Report
@@ Coverage Diff @@
## master #771 +/- ##
==========================================
+ Coverage 96.85% 96.99% +0.14%
==========================================
Files 87 89 +2
Lines 2636 2727 +91
Branches 296 302 +6
==========================================
+ Hits 2553 2645 +92
Misses 50 50
+ Partials 33 32 -1
Continue to review full report at Codecov.
|
And closes #79 =) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work man! 👍 Example of usage looks great!
settings.gradle
Outdated
@@ -1,4 +1,4 @@ | |||
include ':storio-common' | |||
include ':storio-common', ':logginginterceptor' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move to the new line corresponding to other modules declaration?
@NonNull | ||
private final Logger logger; | ||
|
||
public LoggingInterceptor(@NonNull Logger logger) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose make it private and create via static method. To make it easer to support compatibility in the future)
interceptors.addAll(registeredInterceptors); | ||
interceptors.add(realInterceptor); | ||
|
||
return new ChainImpl(interceptors, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe wrap it with unmodifiable container?
@NonNull | ||
private final List<Interceptor> interceptors; | ||
|
||
@NonNull |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excess annotation)
@Nullable // can be null on PreparedGetObject | ||
@Override | ||
public <Result> Result proceed(@NonNull PreparedOperation<Result> operation) { | ||
if (index >= interceptors.size()) throw new AssertionError(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IllegalStateException
with some message?
} | ||
|
||
@NonNull | ||
protected abstract Interceptor getRealInterceptor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe getRealCallInterceptor
or something like this?
} | ||
|
||
private void checkInterceptorsCalls() { | ||
assertThat(callCount.get()).isEqualTo(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add inOrder verification?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange, in my machine tests fail when I mock Interceptor
with some internal Mockito
error. Can you check it on your machine pls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I should update robolectric to support mockito2 (robolectric/robolectric#2677). I will done it soon.
@@ -177,6 +178,9 @@ | |||
@NonNull | |||
public abstract LowLevel lowLevel(); | |||
|
|||
@NonNull |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we will need javadoc for it and for interceptor and chain too=)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff!
@NonNull | ||
private final int index; | ||
|
||
private int calls; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be changed to just a boolean
flag since according to the code we don't really care about actual number of calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually we check that it wasn't called more than once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for boolean)
And should it be thread safe?
} | ||
|
||
// Call the nextChain nextInterceptor in the chain. | ||
final ChainImpl nextChain = new ChainImpl(interceptors, index + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about passing an Iterator
so we can get rid of the index?
final Result result = nextInterceptor.intercept(operation, nextChain); | ||
|
||
// Confirm that the nextChain nextInterceptor made its required call to chain.proceed(). | ||
if (index + 1 < interceptors.size() && nextChain.calls != 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't the same checks be performed inside proceed
of nextChain
?
@NonNull | ||
@Override | ||
protected Interceptor getRealInterceptor() { | ||
return new RealInterceptor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be just an anonymous class (and below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that standalone class is more readable. @nikitin-da what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A agree that variant with standalone class will be more readable.
Also if we will decided some days to make it public, there will be less things to change=)
@@ -62,4 +62,7 @@ | |||
@NonNull | |||
@CheckResult | |||
Single<Result> asRxSingle(); | |||
|
|||
@NonNull | |||
Object getData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about providing some common interface or wrapper to avoid passing plane object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With interface it would be impossible to use third side classes.
We can add generic param to all prepared operation, if you think that it worth doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to try generics in prepared operations, Object
seems too weird…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generics impossible for PreparedGetOperation
, cause it can have either Query
or RawQuery
. We can create common interface for them, but what a point? Anyway, it will not add any details, cause user will see common generic parameter inside Interceptor
which is same as seeing Object
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then you deal with all complaints from users :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JESOS, this is huge, but looks good! Minor comments
@@ -62,4 +62,7 @@ | |||
@NonNull | |||
@CheckResult | |||
Single<Result> asRxSingle(); | |||
|
|||
@NonNull | |||
Object getData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to try generics in prepared operations, Object
seems too weird…
<Result> Result intercept(@NonNull PreparedOperation<Result> operation, @NonNull Chain chain); | ||
|
||
/** | ||
* Encapsulates logic of getting from one interceptor to the next one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of proceeding from one interceptor to another
@Nullable | ||
@Override | ||
public <Result> Result intercept(@NonNull PreparedOperation<Result> operation, @NonNull Chain chain) { | ||
final long startMillis = System.currentTimeMillis(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SystemClock.elapsedRealtime()
|
||
final Result result = chain.proceed(operation); | ||
|
||
final long endMillis = System.currentTimeMillis(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SystemClock.elapsedRealtime()
@artem-zinnatullin we with @nikitin-da decided to add generic param to |
@@ -28,6 +29,28 @@ | |||
public class PreparedGetCursorTest { | |||
|
|||
@Test | |||
public void shouldThrowInNoQueryOrRawQueryIsSet() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if
@@ -62,4 +62,7 @@ | |||
@NonNull | |||
@CheckResult | |||
Single<Result> asRxSingle(); | |||
|
|||
@NonNull | |||
Data getData(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So basically this does not help interceptors to be type-safe but gives a way to get data without need in casting PreparedOperation
to some particular implementation.
I guess we'll have to ship it as 2.x then since it's addition to an interface which is a breaking change (when I was giving greenlight to that I was thinking just about , Data>
generic which is not breaking but forgot that it'll add a method)
…inserts and updates
Hi.
There is a proof of concept for interceptors API and sample
LoggingInterceptor
to see how it works.Main idea of this PR is to create
Interceptor.Chain
in everyPreparedOperation#executeAsBlocking()
method and put in chainRealInterceptor
, which will do real job. So, all code inRealInterceptor#intercept()
is copypaste of pastexecuteAsBlocking()
code.