-
Notifications
You must be signed in to change notification settings - Fork 1
Invoke toJson forcibly even if DataSourceImpl is not public #26
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
base: master
Are you sure you want to change the base?
Conversation
synchronized (toJson) { | ||
try { | ||
toJson.setAccessible(true); | ||
} catch (final SecurityException ex) { | ||
throw new IllegalStateException( | ||
"Method#setAccessible(true) is forbidden for thie method DataSource(Impl)#toJson. " | ||
+ "DataSource class: " + source.getClass().toString() | ||
+ "toJson method: " + toJson.toString(), | ||
ex); | ||
} | ||
|
||
try { | ||
return toJson.invoke(source); | ||
} catch (final InvocationTargetException ex) { | ||
final Throwable targetException = ex.getTargetException(); | ||
if (targetException instanceof RuntimeException) { | ||
throw (RuntimeException) targetException; | ||
} | ||
if (targetException instanceof Error) { | ||
throw (Error) targetException; | ||
} | ||
throw new IllegalStateException("DataSource#toJson() threw unexpected Exception.", targetException); | ||
} catch (final IllegalAccessException ex) { | ||
throw new IllegalStateException( | ||
"DataSource(Impl)#toJson is not accessible even after Method#setAccessible(true). " | ||
+ "DataSource class: " + source.getClass().toString() | ||
+ "toJson method: " + toJson.toString(), | ||
ex); | ||
} finally { | ||
toJson.setAccessible(false); | ||
} | ||
} |
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.
Q: If we narrow the scope of toJson
by obtaining a new local variable Method toJson = getToJsonMethod(source)
, is there a need for synchronizing and restore the accessibility here? In case there's no need, do you still consider it potentially dangerous?
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 thought it can still be dangerous because:
Method#setAccessible
is modifying the "method".- The
toJson
instance, which is retrieved byClass#getMethod("toJson")
, is expected to be the same instance if anotherClass#getMethod("toJson")
is called in another thread.
Yeah, we have to consider a lot of possibility with this type of hacks -- then, as I mentioned, I'm not very positive to merge this.
// then invoking "toJson" of "org.embulk.util.config.DataSourceImpl" caused IllegalAccessException. | ||
// https://github.com/embulk/embulk-util-config/pull/20 | ||
// | ||
// Pass-through to the next step to setAccessible(true) for the "toJson" Method instance. |
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.
Q: I assumed a pass-through here means there's a possibility of another type of exception is thrown but could be resolved with the "accessible = true" hack?
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.
My thought is,
If toJson.invoke(source);
throws a type of Exception:
- If the Exception is
InvocationTargetException
: all rethrown to fail explicittly. - If the Exception is
IllegalAccessException
: passing-through intentionally. - Otherwise: thrown-up to fail.
And those are intended and expected. The case 1 and case 3 should fail immediately. Only the case 2 should pass-through to the next step.
Then, only in the case 2, the accessible flag should be set back false
by toJson.setAccessible(false);
in finally
.
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.
Thanks for your comments!
// then invoking "toJson" of "org.embulk.util.config.DataSourceImpl" caused IllegalAccessException. | ||
// https://github.com/embulk/embulk-util-config/pull/20 | ||
// | ||
// Pass-through to the next step to setAccessible(true) for the "toJson" Method instance. |
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.
My thought is,
If toJson.invoke(source);
throws a type of Exception:
- If the Exception is
InvocationTargetException
: all rethrown to fail explicittly. - If the Exception is
IllegalAccessException
: passing-through intentionally. - Otherwise: thrown-up to fail.
And those are intended and expected. The case 1 and case 3 should fail immediately. Only the case 2 should pass-through to the next step.
Then, only in the case 2, the accessible flag should be set back false
by toJson.setAccessible(false);
in finally
.
synchronized (toJson) { | ||
try { | ||
toJson.setAccessible(true); | ||
} catch (final SecurityException ex) { | ||
throw new IllegalStateException( | ||
"Method#setAccessible(true) is forbidden for thie method DataSource(Impl)#toJson. " | ||
+ "DataSource class: " + source.getClass().toString() | ||
+ "toJson method: " + toJson.toString(), | ||
ex); | ||
} | ||
|
||
try { | ||
return toJson.invoke(source); | ||
} catch (final InvocationTargetException ex) { | ||
final Throwable targetException = ex.getTargetException(); | ||
if (targetException instanceof RuntimeException) { | ||
throw (RuntimeException) targetException; | ||
} | ||
if (targetException instanceof Error) { | ||
throw (Error) targetException; | ||
} | ||
throw new IllegalStateException("DataSource#toJson() threw unexpected Exception.", targetException); | ||
} catch (final IllegalAccessException ex) { | ||
throw new IllegalStateException( | ||
"DataSource(Impl)#toJson is not accessible even after Method#setAccessible(true). " | ||
+ "DataSource class: " + source.getClass().toString() | ||
+ "toJson method: " + toJson.toString(), | ||
ex); | ||
} finally { | ||
toJson.setAccessible(false); | ||
} | ||
} |
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 thought it can still be dangerous because:
Method#setAccessible
is modifying the "method".- The
toJson
instance, which is retrieved byClass#getMethod("toJson")
, is expected to be the same instance if anotherClass#getMethod("toJson")
is called in another thread.
Yeah, we have to consider a lot of possibility with this type of hacks -- then, as I mentioned, I'm not very positive to merge this.
Hi Dai, I understood. Please see this discussion as a sidetrack one and prioritize the other three. It's just interesting to me to discuss on this one out. |
This is where I think I misaligned: IIUC,
Pretty much the same idea as the above, I thought different calls to getMethod returns different metadata instances? (I'm trying to evaluate the "hacki-ness" of this one and weighing the trade-off of having a hard-to-spot bug when this combination of Embulk and embulk-util-config is met (I totally agree that this rarely will happen)). |
Hmm, not sure why this pull-request is closed... |
Reopening. |
AFAIU yes, but actually, not 100% confident. Maybe not. But anyway, the Javadoc does not clearly describe that point. https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean- Also, the specification may change. For instance, Java 11 (or 12?) changed |
As described in #24, this pull-request is to save a case of :
embulk-util-config:0.1.4
or earlier.But, as reviewers can see, this is too hacky, and dangerous potentially. In addition, this is not a critical issue when all the plugins are using
embulk-util-config:0.2.1+
with #24.I basically believe we don't need this although I made this pull-request. (So, this is not included in the Milestone v0.2.1 as of now.)
Wondered if I could have a comment from reviewer(s).