[
https://issues.apache.org/jira/browse/LANG-1685?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18037424#comment-18037424
]
Gary D. Gregory commented on LANG-1685:
---------------------------------------
One simple answer would be: The ReflectionToStringBuilder code is designed to
use certain reflection features, so you must enable those features.
If you are a call site of ReflectionToStringBuilder, you can call toString()
instead, but that's a code change. You'll lose the feature and get completely
different behavior, of course. But you are in control; you decide what your app
or library needs.
If we magically and dynamically disable the internals of
ReflectionToStringBuilder to not use these features under certain conditions,
and use toString() instead, then that's going to be bug reports, for somebody,
probably us as well, with different behavior depending on what Java version is
running.
What worries me is changing behavior without signaling something to the user.
If we do changes at all, should the result string include a message like "This
is a broken string because this feature is not enabled on the JVM command
line"?)
If you use an app stack or library where Lang comes in through a transitive
dependency, then you can't change code. You can enable reflection, though. If
we change the behavior, there are going to be bad surprises, I suspect.
Maybe this is a case where we use a system property that says "Disable advanced
reflection features in ReflectionToStringBuilder". IOW, it's an opt-in.
Looking for comments and opinions.
> [JDK17] ToStringBuilder.reflectionToString fails with
> InaccessibleObjectException on java.lang classes
> ------------------------------------------------------------------------------------------------------
>
> Key: LANG-1685
> URL: https://issues.apache.org/jira/browse/LANG-1685
> Project: Commons Lang
> Issue Type: Bug
> Components: lang.builder.*
> Affects Versions: 3.12.0
> Reporter: David Connard
> Priority: Major
>
> JDK17 prevents reflective access to java.lang classes by default.
> The following code fails on JDK17+
> {code:java}
> System.out.println("boom = " +
> ToStringBuilder.reflectionToString(Set.of(123))); {code}
> I understand that we can "--add-opens" (eg. as you've done for hbase builds
> in
> [https://github.com/jojochuang/hbase/commit/b909db7ca7c221308ad5aba1ea58317c77358b94)]
> ... but, ideally, that should not be a standard requirement to run an
> application that uses {{ToStringBuilder.reflectionToString()}} on JDK17+
> The following sample code appears to work for our use-case, albeit with some
> additional spurious output on the object. It catches the exception and just
> dumps a raw object toString() instead. You probably want to improve on this.
> {code:java}
> ReflectionToStringBuilder jdk17SafeToStringBuilder = new
> ReflectionToStringBuilder(obj) {
> protected void appendFieldsIn(final Class<?> clazz) {
> if (clazz.isArray()) {
> this.reflectionAppendArray(this.getObject());
> return;
> }
> // The elements in the returned array are not sorted and are not in
> any particular order.
> final Field[] fields = clazz.getDeclaredFields();
> Arrays.sort(fields, Comparator.comparing(Field::getName));
> try {
> // first, check that we can delve into the fields. With JDK17+,
> we cannot do this by default on
> // various JDK classes
> AccessibleObject.setAccessible(fields, true);
> } catch (InaccessibleObjectException ioEx) {
> // JDK 17 - prevents access to fields. We'll ignore this, and
> assume these have a decent toString() and not reflect into them
> this.appendToString(Objects.toString(obj));
> return;
> }
> for (final Field field : fields) {
> final String fieldName = field.getName();
> if (this.accept(field)) {
> try {
> // Warning: Field.get(Object) creates wrappers objects
> // for primitive types.
> final Object fieldValue = this.getValue(field);
> if (!isExcludeNullValues() || fieldValue != null) {
> this.append(fieldName, fieldValue,
> !field.isAnnotationPresent(ToStringSummary.class));
> }
> } catch (final IllegalAccessException ex) {
> //this can't happen. Would get a Security exception
> // instead
> //throw a runtime exception in case the impossible
> // happens.
> throw new InternalError("Unexpected
> IllegalAccessException: " + ex.getMessage());
> }
> }
> }
> }
> };
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)