-
-
Notifications
You must be signed in to change notification settings - Fork 274
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
Take advantage of Java 5 language features #389
Conversation
@@ -360,7 +360,7 @@ boolean isRecording() { | |||
synchronized <T> int export(@Nonnull Class<T> clazz, @CheckForNull T t, boolean notifyListener) { | |||
if(t==null) return 0; // bootstrap classloader | |||
|
|||
Entry e = reverse.get(t); | |||
Entry<T> e = (Entry<T>) reverse.get(t); |
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.
This cast is safe, as can be seen by reading the surrounding code that places entries into the map. The keys of the map are of type Object
and the values are of type Entry
. The only time that we ever add something to the map, the Object
is parameterized on T
and the Entry
is also parameterized on the same T
.
@@ -79,7 +79,7 @@ | |||
*/ | |||
private int lastIoId; | |||
|
|||
private volatile Response<RSP,EXC> response; | |||
private volatile Response<RSP,? extends Throwable> response; |
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.
The original type parameter was wrong. Fortunately, this never resulted in any actual bugs due to type erasure. The reasoning is as follows. The EXC
type parameter in the Request
class represents the bound for the exception types that subclasses of Request
may produce. The Response
class may include exceptions of these types, but it may also include an exception of type RequestAbortedException
(see Request#abort(IOException)
). Recall that this field is in the Request
class, so EXC
represents the bound on the request's exception types, not the response's exception types. To keep supporting Request#abort(IOException)
, the bound here must be able to include RequestAbortedException
. So the bound for EXC
is not large enough, so we must include all instances of Throwable
. This also prevents us from having to make a risky change to the Runnable
in Request#execute
.
@@ -192,10 +192,10 @@ final RSP call(Channel channel) throws EXC, InterruptedException, IOException { | |||
// ignore the I/O error | |||
} | |||
|
|||
Object exc = response.exception; | |||
Throwable exc = response.exception; |
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.
response.exception
was always of type Throwable
, so this was just unnecessary.
@@ -341,7 +341,7 @@ public RSP get(long timeout, TimeUnit unit) throws InterruptedException, Executi | |||
* Aborts the processing. The calling thread will receive an exception. | |||
*/ | |||
/*package*/ void abort(IOException e) { | |||
onCompleted(new Response(this, id, 0, new RequestAbortedException(e))); | |||
onCompleted(new Response<>(this, id, 0, new RequestAbortedException(e))); |
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.
This change would not have worked if we had not expanded the bound above to be able to include RequestAbortedException
.
@@ -36,7 +37,7 @@ | |||
* @see Request | |||
* @since 3.17 | |||
*/ | |||
public final class Response<RSP,EXC extends Throwable> extends Command { | |||
public final class Response<RSP extends Serializable,EXC extends Throwable> extends Command { |
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.
Instances of Response
are always created from instances of Request
, whose RSP
type parameter is bounded by Serializable
. So there is no reason not to similarly bound the type parameter of Response
. Doing so makes the relationship between the two more clear. Note that the bound of the EXC
type parameter on the Response
class may be different (broader) than that of the Request
class due to the fact that a response may include a RequestAbortedException
as described above.
@@ -59,17 +60,17 @@ | |||
@SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Only supposed to be defined on one side.") | |||
private transient long totalTime; | |||
@SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Bound after deserialization, in execute.") | |||
private transient Request<?, ?> request; | |||
private transient Request<RSP, ? extends Throwable> request; |
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.
As in Request
, we cannot use EXC
here because the bound for the Response
exception must be larger than those of the Request
exception.
@@ -82,7 +83,7 @@ | |||
*/ | |||
@Override | |||
void execute(Channel channel) { | |||
Request req = channel.pendingCalls.get(id); | |||
Request<RSP, ? extends Throwable> req = (Request<RSP, ? extends Throwable>) channel.pendingCalls.get(id); |
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.
This cast is safe because the RSP
type parameter shares the same bounds for a Request
and its Response
.
My CI run "failed" in the Windows branch, but this failure is spurious because the |
Let's try running the CI again. |
Build now passes. I'll take a look at the proposal when I get the chance. |
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.
Nice improvements. This will help the maintainability and readability.
Thanks for the submission.
Thank you for the review! |
Downstream of #388. This PR updates the code base to take full advantage of Java 5 language features; namely, enhanced
for
and generics. There are two commits in this change (on top of the commit from #388). I suggest reviewing each commit separately. The first commit should be fairly self-explanatory and replaces anyfor
loops with Java 5 enhancedfor
. The second commit adds generics to any types that were missing them and also tightens the bounds of these generics. I will explain these changes in a review.This change may appear risky at first glance but it is actually completely safe due to the fact that no runtime code is affected. Yes, type parameters have been changed, but they only affect compilation and not runtime due to type erasure. There are only two places where I introduced casts in non-test code, but those casts are safe because they only cast from one set of type parameters to another set of type parameters (not from one type of object to another type of object). In other words, there is no runtime impact whatsoever.