David Connard created LANG-1685:
-----------------------------------
Summary: [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
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.1#820001)