#384: 2.0.1 API imports org.eclipse.jsonp by OSGi headers Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/api/pom.xml b/api/pom.xml index b077e66..b9980fb 100644 --- a/api/pom.xml +++ b/api/pom.xml
@@ -341,6 +341,12 @@ <Bundle-Description>Jakarta JSON Processing API ${spec.version}</Bundle-Description> <Specification-Vendor>${vendor.name}</Specification-Vendor> <Implementation-Build-Id>${buildNumber}</Implementation-Build-Id> + <DynamicImport-Package>*</DynamicImport-Package> + <Import-Package> + !org.glassfish.hk2.osgiresourcelocator, + !org.glassfish.json, + * + </Import-Package> </instructions> </configuration> <executions>
diff --git a/api/src/main/java/jakarta/json/spi/JsonProvider.java b/api/src/main/java/jakarta/json/spi/JsonProvider.java index ea56275..15d7aee 100644 --- a/api/src/main/java/jakarta/json/spi/JsonProvider.java +++ b/api/src/main/java/jakarta/json/spi/JsonProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -25,6 +25,7 @@ import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Iterator; import java.util.Map; @@ -68,9 +69,19 @@ if (it.hasNext()) { return it.next(); } + + // handling OSGi (specific default) + if (isOsgi()) { + JsonProvider result = lookupUsingOSGiServiceLoader(JsonProvider.class); + if (result != null) { + return result; + } + } + try { + checkPackageAccess(DEFAULT_PROVIDER); Class<?> clazz = Class.forName(DEFAULT_PROVIDER); - return (JsonProvider) clazz.newInstance(); + return (JsonProvider) clazz.getConstructor().newInstance(); } catch (ClassNotFoundException x) { throw new JsonException( "Provider " + DEFAULT_PROVIDER + " not found", x); @@ -477,4 +488,58 @@ public JsonNumber createValue(BigInteger value) { throw new UnsupportedOperationException(); } + + /** OSGI aware service loader by HK2 */ + private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; + + /** + * Check availability of HK2 service loader. + * + * @return true if HK2 service locator is available + */ + private static boolean isOsgi() { + checkPackageAccess(OSGI_SERVICE_LOADER_CLASS_NAME); + try { + Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); + return true; + } catch (ClassNotFoundException ignored) { + } + return false; + } + + /** + * Lookup the service class by the HK2 service locator. + * + * @param serviceClass service class + * @param <T> type of the service + * @return a provider + */ + private static <T> T lookupUsingOSGiServiceLoader(Class<? extends T> serviceClass) { + try { + // Use reflection to avoid having any dependendcy on HK2 ServiceLoader class + Class<?>[] args = new Class<?>[]{serviceClass}; + Class<?> target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); + Method m = target.getMethod("lookupProviderInstances", Class.class); + @SuppressWarnings({"unchecked"}) + Iterator<? extends T> iter = ((Iterable<? extends T>) m.invoke(null, (Object[]) args)).iterator(); + return iter.hasNext() ? iter.next() : null; + } catch (Exception ignored) { + // log and continue + return null; + } + } + + /** + * Make sure that the current thread has an access to the package of the given name. + * @param className The class name to check. + */ + private static void checkPackageAccess(String className) { + SecurityManager s = System.getSecurityManager(); + if (s != null) { + int i = className.lastIndexOf('.'); + if (i != -1) { + s.checkPackageAccess(className.substring(0, i)); + } + } + } }