diff --git a/api/src/main/java/jakarta/json/spi/JsonProvider.java b/api/src/main/java/jakarta/json/spi/JsonProvider.java index 13f89dbc..28fe280a 100644 --- a/api/src/main/java/jakarta/json/spi/JsonProvider.java +++ b/api/src/main/java/jakarta/json/spi/JsonProvider.java @@ -23,11 +23,15 @@ import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.logging.Logger; import jakarta.json.JsonArray; import jakarta.json.JsonArrayBuilder; @@ -74,6 +78,9 @@ public abstract class JsonProvider { private static final String DEFAULT_PROVIDER = "org.eclipse.parsson.JsonProviderImpl"; + /** A logger */ + private static final Logger LOG = Logger.getLogger(JsonProvider.class.getName()); + /** * Default constructor. */ @@ -100,48 +107,62 @@ protected JsonProvider() { * @return a JSON provider */ public static JsonProvider provider() { - if (LazyFactoryLoader.JSON_PROVIDER != null) { - return newInstance(LazyFactoryLoader.JSON_PROVIDER); + LOG.log(Level.FINE, "Checking system property {0}", JSONP_PROVIDER_FACTORY); + final String factoryClassName = System.getSecurityManager() != null + ? AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty(JSONP_PROVIDER_FACTORY)) + : System.getProperty(JSONP_PROVIDER_FACTORY); + if (factoryClassName != null) { + JsonProvider provider = newInstance(factoryClassName); + LOG.log(Level.FINE, "System property used; returning object [{0}]", + provider.getClass().getName()); + return provider; } + + LOG.log(Level.FINE, "Checking ServiceLoader"); ServiceLoader loader = ServiceLoader.load(JsonProvider.class); Iterator it = loader.iterator(); if (it.hasNext()) { - return it.next(); + JsonProvider provider = it.next(); + LOG.log(Level.FINE, "ServiceLoader loading Facility used; returning object [{0}]", + provider.getClass().getName()); + return provider; } // handling OSGi (specific default) if (isOsgi()) { - JsonProvider result = lookupUsingOSGiServiceLoader(JsonProvider.class); - if (result != null) { - return result; + LOG.log(Level.FINE, "Checking OSGi"); + JsonProvider provider = lookupUsingOSGiServiceLoader(JsonProvider.class); + if (provider != null) { + LOG.log(Level.FINE, "OSGi loading facility used; returning object [{0}].", + provider.getClass().getName()); + return provider; } } - try { - Class clazz = Class.forName(DEFAULT_PROVIDER); - return (JsonProvider) clazz.getConstructor().newInstance(); - } catch (ClassNotFoundException x) { - throw new JsonException( - "Provider " + DEFAULT_PROVIDER + " not found", x); - } catch (Exception x) { - throw new JsonException( - "Provider " + DEFAULT_PROVIDER + " could not be instantiated: " + x, - x); - } + // else no provider found + LOG.fine("Trying to create the platform default provider"); + return newInstance(DEFAULT_PROVIDER); } /** * Creates a new instance from the specified class - * @param clazz class to instance + * @param className name of the class to instantiate * @return the JsonProvider instance - * @throws IllegalArgumentException for reflection issues + * @throws JsonException for issues during creation of an instance of the JsonProvider */ - private static JsonProvider newInstance(Class clazz) { - checkPackageAccess(clazz.getName()); + private static JsonProvider newInstance(String className) { try { + checkPackageAccess(className); + @SuppressWarnings({"unchecked"}) + Class clazz = (Class) Class.forName(className); return clazz.getConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException("Unable to create " + clazz.getName(), e); + } catch (ClassNotFoundException x) { + throw new JsonException( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new JsonException( + "Provider " + className + " could not be instantiated: " + x, + x); } } @@ -617,37 +638,10 @@ private static T lookupUsingOSGiServiceLoader(Class serviceClas @SuppressWarnings({"unchecked"}) Iterator iter = ((Iterable) m.invoke(null, (Object[]) args)).iterator(); return iter.hasNext() ? iter.next() : null; - } catch (Exception ignored) { - // log and continue + } catch (Exception ex) { + LOG.log(Level.FINE, "Unable to find from OSGi: [" + serviceClass.getName() + "]", ex); return null; } } - /** - * Lazy loads the class specified in System property with the key JSONP_PROVIDER_FACTORY. - * If no property is set, the value of {@link #JSON_PROVIDER} will be null. - * In case of errors an IllegalStateException is thrown. - * - */ - @SuppressWarnings("unchecked") - private static class LazyFactoryLoader { - - /** - * JSON provider class - */ - private static final Class JSON_PROVIDER; - - static { - String className = System.getProperty(JSONP_PROVIDER_FACTORY); - if (className != null) { - try { - JSON_PROVIDER = (Class) Class.forName(className); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Unable to create " + className, e); - } - } else { - JSON_PROVIDER = null; - } - } - } } diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 12cd6ba9..aad8a0e0 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -18,6 +18,7 @@ * Jakarta JSON Processing API. */ module jakarta.json { + requires java.logging; exports jakarta.json; exports jakarta.json.spi; exports jakarta.json.stream; diff --git a/tck/tck-tests/src/main/java/ee/jakarta/tck/jsonp/api/provider/JsonProviderTest.java b/tck/tck-tests/src/main/java/ee/jakarta/tck/jsonp/api/provider/JsonProviderTest.java index 6cb37497..17731d23 100644 --- a/tck/tck-tests/src/main/java/ee/jakarta/tck/jsonp/api/provider/JsonProviderTest.java +++ b/tck/tck-tests/src/main/java/ee/jakarta/tck/jsonp/api/provider/JsonProviderTest.java @@ -34,6 +34,8 @@ import jakarta.json.stream.JsonGeneratorFactory; import jakarta.json.stream.JsonParser; import jakarta.json.stream.JsonParserFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,7 +48,23 @@ public class JsonProviderTest { private static final String JSONP_PROVIDER_FACTORY = "jakarta.json.provider"; - + private String factoryValue; + + @BeforeEach + public void setUp() { + factoryValue = System.getProperty(JSONP_PROVIDER_FACTORY); + System.clearProperty(JSONP_PROVIDER_FACTORY); + } + + @AfterEach + public void reset() { + if (factoryValue != null) { + System.setProperty(JSONP_PROVIDER_FACTORY, factoryValue); + } else { + System.clearProperty(JSONP_PROVIDER_FACTORY); + } + } + /** * Verifies it is possible to obtain the JsonProvider implementation from a System property. */