From 5bf362a96438e192ccc8a2b854797f5428341580 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Fri, 20 Sep 2024 09:53:48 +0200 Subject: [PATCH] Add File and Path as string primitive Since jdk 17 it's not possible to do deep reflection. The content of File or Path instances are difficult to see content with deep reflection, though the meaningful value is the toString representation We are adding File and Path instances serialized as string primitive and evaluated in EL as String as well --- .../debugger/util/WellKnownClasses.java | 61 ++++++++++--------- .../agent/SnapshotSerializationTest.java | 8 +++ 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/util/WellKnownClasses.java b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/util/WellKnownClasses.java index b6e2b2da9c3..c9b9ef5f50c 100644 --- a/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/util/WellKnownClasses.java +++ b/dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/util/WellKnownClasses.java @@ -26,24 +26,24 @@ public class WellKnownClasses { static { TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Class", WellKnownClasses::classToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.String", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Boolean", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Integer", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Long", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Double", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Character", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Byte", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Float", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Short", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.math.BigDecimal", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.math.BigInteger", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.time.Duration", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.time.Instant", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalTime", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalDate", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalDateTime", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.util.UUID", WellKnownClasses::genericToString); - TO_STRING_FINAL_SAFE_CLASSES.put("java.net.URI", WellKnownClasses::genericToString); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.String", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Boolean", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Integer", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Long", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Double", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Character", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Byte", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Float", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.lang.Short", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.math.BigDecimal", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.math.BigInteger", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.time.Duration", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.time.Instant", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalTime", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalDate", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.time.LocalDateTime", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.util.UUID", String::valueOf); + TO_STRING_FINAL_SAFE_CLASSES.put("java.net.URI", String::valueOf); } private static final Map> SAFE_TO_STRING_FUNCTIONS = @@ -51,12 +51,13 @@ public class WellKnownClasses { static { SAFE_TO_STRING_FUNCTIONS.putAll(TO_STRING_FINAL_SAFE_CLASSES); - SAFE_TO_STRING_FUNCTIONS.put( - "java.util.concurrent.atomic.AtomicBoolean", WellKnownClasses::genericToString); - SAFE_TO_STRING_FUNCTIONS.put( - "java.util.concurrent.atomic.AtomicInteger", WellKnownClasses::genericToString); - SAFE_TO_STRING_FUNCTIONS.put( - "java.util.concurrent.atomic.AtomicLong", WellKnownClasses::genericToString); + SAFE_TO_STRING_FUNCTIONS.put("java.util.concurrent.atomic.AtomicBoolean", String::valueOf); + SAFE_TO_STRING_FUNCTIONS.put("java.util.concurrent.atomic.AtomicInteger", String::valueOf); + SAFE_TO_STRING_FUNCTIONS.put("java.util.concurrent.atomic.AtomicLong", String::valueOf); + SAFE_TO_STRING_FUNCTIONS.put("java.io.File", String::valueOf); + // implementations of java.io.file.Path interfaces + SAFE_TO_STRING_FUNCTIONS.put("sun.nio.fs.UnixPath", String::valueOf); + SAFE_TO_STRING_FUNCTIONS.put("sun.nio.fs.WindowsPath", String::valueOf); } private static final Set EQUALS_SAFE_CLASSES = new HashSet<>(); @@ -81,6 +82,9 @@ public class WellKnownClasses { EQUALS_SAFE_CLASSES.add("java.time.LocalDateTime"); EQUALS_SAFE_CLASSES.add("java.util.UUID"); EQUALS_SAFE_CLASSES.add("java.net.URI"); + EQUALS_SAFE_CLASSES.add("java.io.File"); + EQUALS_SAFE_CLASSES.add("sun.nio.fs.UnixPath"); + EQUALS_SAFE_CLASSES.add("sun.nio.fs.WindowsPath"); } private static final Set STRING_PRIMITIVES = @@ -93,7 +97,10 @@ public class WellKnownClasses { "java.time.LocalTime", "java.time.LocalDate", "java.time.LocalDateTime", - "java.util.UUID")); + "java.util.UUID", + "java.io.File", + "sun.nio.fs.UnixPath", + "sun.nio.fs.WindowsPath")); private static final Map, Map>> SPECIAL_TYPE_ACCESS = new HashMap<>(); @@ -236,10 +243,6 @@ private static String classToString(Object o) { return ((Class) o).getTypeName(); } - private static String genericToString(Object o) { - return String.valueOf(o); - } - public static boolean isEqualsSafe(Class clazz) { return clazz.isPrimitive() || clazz.isEnum() diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SnapshotSerializationTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SnapshotSerializationTest.java index 9830772aca0..2f6f3acdec6 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SnapshotSerializationTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SnapshotSerializationTest.java @@ -40,12 +40,14 @@ import datadog.trace.bootstrap.debugger.ProbeLocation; import datadog.trace.bootstrap.debugger.util.TimeoutChecker; import datadog.trace.test.util.Flaky; +import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.math.BigDecimal; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Path; import java.time.Duration; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; @@ -308,6 +310,8 @@ static class WellKnownClasses { OptionalLong maybeLong = OptionalLong.of(84); Exception ex = new IllegalArgumentException("invalid arg"); StackTraceElement element = new StackTraceElement("Foo", "bar", "foo.java", 42); + File file = new File("/tmp/foo"); + Path path = file.toPath(); } @Test @@ -384,6 +388,10 @@ public void wellKnownClasses() throws IOException { assertPrimitiveValue(elementFields, "methodName", String.class.getTypeName(), "bar"); assertPrimitiveValue(elementFields, "fileName", String.class.getTypeName(), "foo.java"); assertPrimitiveValue(elementFields, "lineNumber", Integer.class.getTypeName(), "42"); + // file + assertPrimitiveValue(objLocalFields, "file", File.class.getTypeName(), "/tmp/foo"); + // path + assertPrimitiveValue(objLocalFields, "path", "sun.nio.fs.UnixPath", "/tmp/foo"); } @Test