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)

Reply via email to