From e307ae40100f5ba60af447a7c864c07eaf83f568 Mon Sep 17 00:00:00 2001 From: Jesse Gallagher Date: Fri, 29 Mar 2024 14:49:49 -0400 Subject: [PATCH] =?UTF-8?q?Modify=20JNXServiceFinder=20to=20also=20check?= =?UTF-8?q?=20the=20service=20class=E2=80=99s=20ClassLoader=20(Issue=20#41?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hcl/domino/misc/JNXServiceFinder.java | 19 +++++++++++++++---- .../data/TestDocumentValueConversion.java | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/domino-jnx-api/src/main/java/com/hcl/domino/misc/JNXServiceFinder.java b/domino-jnx-api/src/main/java/com/hcl/domino/misc/JNXServiceFinder.java index 5e45cb08b..f5c6d216f 100644 --- a/domino-jnx-api/src/main/java/com/hcl/domino/misc/JNXServiceFinder.java +++ b/domino-jnx-api/src/main/java/com/hcl/domino/misc/JNXServiceFinder.java @@ -19,13 +19,14 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; +import java.util.Comparator; import java.util.Map; import java.util.NoSuchElementException; import java.util.ServiceLoader; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; /** * Utility class to coordinate service loading for JNX. @@ -81,9 +82,19 @@ public static T findRequiredService(final Class serviceClass, final Class @SuppressWarnings("unchecked") public static Stream findServices(final Class serviceClass) { return (Stream)SERVICE_CACHE.computeIfAbsent(serviceClass, c -> { - final Iterable services = AccessController + Set converters = new TreeSet<>(Comparator.comparing(o -> o.getClass().getName())); + + // Check the context (app) ClassLoader + Iterable services = AccessController .doPrivileged((PrivilegedAction>) () -> ServiceLoader.load(serviceClass)); - return StreamSupport.stream(services.spliterator(), false).collect(Collectors.toList()); + services.forEach(converters::add); + + // Also check the service's own ClassLoader, as it may be distinct + services = AccessController + .doPrivileged((PrivilegedAction>) () -> ServiceLoader.load(serviceClass, serviceClass.getClassLoader())); + services.forEach(converters::add); + + return converters; }).stream(); } } diff --git a/test/it-domino-jnx/src/test/java/it/com/hcl/domino/test/data/TestDocumentValueConversion.java b/test/it-domino-jnx/src/test/java/it/com/hcl/domino/test/data/TestDocumentValueConversion.java index e52cd2767..2e36ddd78 100644 --- a/test/it-domino-jnx/src/test/java/it/com/hcl/domino/test/data/TestDocumentValueConversion.java +++ b/test/it-domino-jnx/src/test/java/it/com/hcl/domino/test/data/TestDocumentValueConversion.java @@ -17,6 +17,7 @@ package it.com.hcl.domino.test.data; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; import java.time.OffsetDateTime; @@ -377,4 +378,17 @@ public void testTimeRoundTrip() throws Exception { Assertions.assertEquals(LocalTime.from(expected), LocalTime.from(date)); }); } + + @Test + public void testInstantRoundTrip() throws Exception { + final Instant expected = Instant.ofEpochSecond(System.currentTimeMillis() / 1000); + + withTempDb(database -> { + final Document doc = database.createDocument(); + + doc.replaceItemValue("Foo", expected); + final Instant date = doc.get("Foo", Instant.class, null); + Assertions.assertEquals(Instant.from(expected), Instant.from(date)); + }); + } }