From 43826db542084db7b5d784a6ba89634b008c1e93 Mon Sep 17 00:00:00 2001 From: Mateusz Szygenda Date: Wed, 1 Feb 2023 10:36:54 +0100 Subject: [PATCH] fixes walking over internal JDK11 fields This is a backport of a fix developed in: Original Author: @mprusakov https://github.com/ehcache/sizeof/pull/61 https://github.com/ehcache/sizeof/issues/54 Also adds unit test for that issue. --- .../pool/sizeof/ObjectGraphWalker.java | 5 ++++ .../pool/sizeof/ObjectGraphWalkerTest.java | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/ehcache-core/src/main/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalker.java b/ehcache-core/src/main/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalker.java index 5f0e1a1e16..6bbc7f86e9 100644 --- a/ehcache-core/src/main/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalker.java +++ b/ehcache-core/src/main/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalker.java @@ -273,7 +273,12 @@ private static Collection getAllFields(Class refClass) { LOG.error("Security settings prevent Ehcache from accessing the subgraph beneath '{}'" + " - cache sizes may be underestimated as a result", field, e); continue; + } catch (RuntimeException e) { + LOG.warn("The JVM is preventing Ehcache from accessing the subgraph beneath '{}'" + + " - cache sizes may be underestimated as a result", field, e); + continue; } + fields.add(field); } } diff --git a/ehcache-core/src/test/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalkerTest.java b/ehcache-core/src/test/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalkerTest.java index 8e5ba06c69..0abb8d966b 100644 --- a/ehcache-core/src/test/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalkerTest.java +++ b/ehcache-core/src/test/java/net/sf/ehcache/pool/sizeof/ObjectGraphWalkerTest.java @@ -6,6 +6,8 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.net.URL; +import java.net.URLClassLoader; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -63,6 +65,7 @@ public void increment(String value) { assertThat(map.isEmpty(), is(true)); assertThat(walker.walk(MAX_SIZEOF_DEPTH, false, new SomeInnerClass()), is(14L)); + assertThat(map.remove("java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter"), is(1L)); assertThat(map.remove(SomeInnerClass.class.getName()), is(1L)); @@ -91,6 +94,30 @@ public class SomeInnerClass { private final Object four = new ReentrantReadWriteLock(); private final Object[] anArray = new Object[]{new Object(), new Object(), new Object(), one, two, two, three, four, value}; private final int[] anIntArray = new int[] {1, 2, 1300 }; + } + + @Test + public void testWalksAGraphWithInacessibleFieldsWithoutThrowingException() { + class ClassWithNestedInacessibleFields { + /** + * Certain fields of JDK11 classes are internal and throw new kind of exception upon reflection access + * + * java.lang.reflect.InaccessibleObjectException: Unable to make field final jdk.internal.loader.URLClassPath jdk.internal.loader.ClassLoaders$AppClassLoader.ucp accessible: module java.base does not "opens jdk.internal.loader" + */ + public final URLClassLoader objectWithInaccessibleFields = new URLClassLoader(new URL[]{}); + } + + ObjectGraphWalker walker = new ObjectGraphWalker( + new ObjectGraphWalker.Visitor() { + @Override + public long visit(Object object) { + return 0; + } + }, new PassThroughFilter() + ); + walker.walk(MAX_SIZEOF_DEPTH, false, new ClassWithNestedInacessibleFields()); } + + }