Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 46 additions & 52 deletions api/src/main/java/jakarta/json/spi/JsonProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*/
Expand All @@ -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<String>) () -> 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<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
Iterator<JsonProvider> 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<? extends JsonProvider> clazz) {
checkPackageAccess(clazz.getName());
private static JsonProvider newInstance(String className) {
try {
checkPackageAccess(className);
@SuppressWarnings({"unchecked"})
Class<JsonProvider> clazz = (Class<JsonProvider>) 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);
}
}

Expand Down Expand Up @@ -617,37 +638,10 @@ private static <T> T lookupUsingOSGiServiceLoader(Class<? extends T> serviceClas
@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
} 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<? extends JsonProvider> JSON_PROVIDER;

static {
String className = System.getProperty(JSONP_PROVIDER_FACTORY);
if (className != null) {
try {
JSON_PROVIDER = (Class<? extends JsonProvider>) Class.forName(className);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Unable to create " + className, e);
}
} else {
JSON_PROVIDER = null;
}
}
}
}
3 changes: 2 additions & 1 deletion api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
*/
Expand Down