/*
 * Copyright (c) 2012, 2019 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
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.server;

import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import javax.ws.rs.Path;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configurable;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Feature;

import org.glassfish.jersey.internal.Errors;
import org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFactory;
import org.glassfish.jersey.internal.inject.Binder;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.spi.AutoDiscoverable;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.Tokenizer;
import org.glassfish.jersey.model.ContractProvider;
import org.glassfish.jersey.model.internal.CommonConfig;
import org.glassfish.jersey.model.internal.ComponentBag;
import org.glassfish.jersey.model.internal.ManagedObjectsFinalizer;
import org.glassfish.jersey.process.Inflector;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener;
import org.glassfish.jersey.server.internal.scanning.FilesScanner;
import org.glassfish.jersey.server.internal.scanning.PackageNamesScanner;
import org.glassfish.jersey.server.model.Resource;


The resource configuration for configuring a web application.
Author:Paul Sandoz, Martin Matula, Michal Gajdos, Marek Potociar
/** * The resource configuration for configuring a web application. * * @author Paul Sandoz * @author Martin Matula * @author Michal Gajdos * @author Marek Potociar */
public class ResourceConfig extends Application implements Configurable<ResourceConfig>, ServerConfig { private static final Logger LOGGER = Logger.getLogger(ResourceConfig.class.getName()); private transient Set<Class<?>> cachedClasses = null; private transient Set<Class<?>> cachedClassesView = null; private transient Set<Object> cachedSingletons = null; private transient Set<Object> cachedSingletonsView = null; private transient boolean resetFinders = false; private volatile State state; private static class State extends CommonConfig implements ServerConfig { private final Set<ResourceFinder> resourceFinders; private final Set<Resource> resources; private final Set<Resource> resourcesView; private volatile String applicationName; private volatile ClassLoader classLoader = null; public State() { super(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL); this.classLoader = AccessController.doPrivileged(ReflectionHelper.getContextClassLoaderPA()); this.resourceFinders = new HashSet<>(); this.resources = new HashSet<>(); this.resourcesView = Collections.unmodifiableSet(this.resources); } public State(final State original) { super(original); this.classLoader = original.classLoader; this.applicationName = original.applicationName; this.resources = new HashSet<>(original.resources); this.resourcesView = Collections.unmodifiableSet(this.resources); this.resourceFinders = new HashSet<>(original.resourceFinders); } public void setClassLoader(final ClassLoader classLoader) { this.classLoader = classLoader; } public void setApplicationName(final String applicationName) { this.applicationName = applicationName; } public void registerResources(final Set<Resource> resources) { this.resources.addAll(resources); } public void registerFinder(final ResourceFinder resourceFinder) { this.resourceFinders.add(resourceFinder); } @Override protected Inflector<ContractProvider.Builder, ContractProvider> getModelEnhancer(final Class<?> componentClass) { return builder -> { if (builder.getScope() == null && builder.getContracts().isEmpty() && Resource.getPath(componentClass) != null) { builder.scope(RequestScoped.class); } return builder.build(); }; } @Override public State loadFrom(final Configuration config) { super.loadFrom(config); this.resourceFinders.clear(); this.resources.clear(); State other = null; if (config instanceof ResourceConfig) { other = ((ResourceConfig) config).state; } if (config instanceof State) { other = (State) config; } if (other != null) { this.resourceFinders.addAll(other.resourceFinders); this.resources.addAll(other.resources); } return this; } @Override public final Set<Resource> getResources() { return resourcesView; } @Override public ServerConfig getConfiguration() { return this; }
Get the registered resource finders.
Returns:registered resource finders.
/** * Get the registered resource finders. * * @return registered resource finders. */
public Set<ResourceFinder> getResourceFinders() { return resourceFinders; }
Get resource and provider class loader.
Returns:class loader to be used when looking up the resource classes and providers.
/** * Get resource and provider class loader. * * @return class loader to be used when looking up the resource classes and providers. */
public ClassLoader getClassLoader() { return classLoader; } private String getApplicationName() { return applicationName; } } private static final class ImmutableState extends State { private ImmutableState(final State original) { super(original); } @Override public void setClassLoader(final ClassLoader classLoader) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public void registerResources(final Set<Resource> resources) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public void registerFinder(final ResourceFinder resourceFinder) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State addProperties(final Map<String, ?> properties) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State property(final String name, final Object value) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Class<?> componentClass) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Class<?> componentClass, final int bindingPriority) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Class<?> componentClass, final Class<?>... contracts) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Class<?> componentClass, final Map<Class<?>, Integer> contracts) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Object component) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Object component, final int bindingPriority) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Object component, final Class<?>... contracts) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State register(final Object component, final Map<Class<?>, Integer> contracts) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public State setProperties(final Map<String, ?> properties) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public void configureAutoDiscoverableProviders(final InjectionManager injectionManager, final Collection<AutoDiscoverable> autoDiscoverables, final boolean forcedOnly) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } @Override public void configureMetaProviders(final InjectionManager injectionManager, final ManagedObjectsFinalizer finalizer) { throw new IllegalStateException(LocalizationMessages.RC_NOT_MODIFIABLE()); } }
Returns a ResourceConfig instance for the supplied application.

If the application is an instance of ResourceConfig the method returns defensive copy of the resource config. Otherwise it creates a new ResourceConfig from the application.
Params:
  • application – Application to provide the ResourceConfig instance for.
Returns:ResourceConfig instance for the supplied application.
/** * Returns a {@code ResourceConfig} instance for the supplied application. * <p/> * If the application is an instance of {@code ResourceConfig} the method returns defensive copy of the resource config. * Otherwise it creates a new {@code ResourceConfig} from the application. * * @param application Application to provide the {@code ResourceConfig} instance for. * @return ResourceConfig instance for the supplied application. */
public static ResourceConfig forApplication(final Application application) { return application instanceof ResourceConfig ? ((ResourceConfig) application) : new WrappingResourceConfig(application, null, null); }
Returns a ResourceConfig instance wrapping the application of the supplied class.
Params:
  • applicationClass – Class representing a JAX-RS application.
Returns:ResourceConfig wrapping the JAX-RS application defined by the supplied class.
/** * Returns a {@code ResourceConfig} instance wrapping the application of the supplied class. * * @param applicationClass Class representing a JAX-RS application. * @return ResourceConfig wrapping the JAX-RS application defined by the supplied class. */
public static ResourceConfig forApplicationClass(final Class<? extends Application> applicationClass) { return new WrappingResourceConfig(null, applicationClass, null); }
Returns a ResourceConfig instance wrapping the application of the supplied class.

This method provides an option of supplying the set of classes that should be returned from getClasses() method if the application defined by the supplied application class returns empty sets from Application.getClasses() and Application.getSingletons() methods.
Params:
  • applicationClass – Class representing a JAX-RS application.
  • defaultClasses – Default set of classes that should be returned from getClasses() if the underlying application does not provide any classes and singletons.
Returns:ResourceConfig wrapping the JAX-RS application defined by the supplied class.
/** * Returns a {@code ResourceConfig} instance wrapping the application of the supplied class. * <p/> * This method provides an option of supplying the set of classes that should be returned from {@link #getClasses()} * method if the application defined by the supplied application class returns empty sets from * {@link javax.ws.rs.core.Application#getClasses()} * and {@link javax.ws.rs.core.Application#getSingletons()} methods. * * @param applicationClass Class representing a JAX-RS application. * @param defaultClasses Default set of classes that should be returned from {@link #getClasses()} if the underlying * application does not provide any classes and singletons. * @return ResourceConfig wrapping the JAX-RS application defined by the supplied class. */
public static ResourceConfig forApplicationClass(final Class<? extends Application> applicationClass, final Set<Class<?>> defaultClasses) { return new WrappingResourceConfig(null, applicationClass, defaultClasses); }
Create a new resource configuration without any custom properties or resource and provider classes.
/** * Create a new resource configuration without any custom properties or * resource and provider classes. */
public ResourceConfig() { this.state = new State(); }
Create a new resource configuration initialized with a given set of resource/provider classes.
Params:
  • classes – application-specific resource and/or provider classes.
/** * Create a new resource configuration initialized with a given set of * resource/provider classes. * * @param classes application-specific resource and/or provider classes. */
public ResourceConfig(final Set<Class<?>> classes) { this(); this.registerClasses(classes); }
Create a new resource configuration initialized with a given set of resource/provider classes.
Params:
  • classes – application-specific resource and/or provider classes.
/** * Create a new resource configuration initialized with a given set of * resource/provider classes. * * @param classes application-specific resource and/or provider classes. */
public ResourceConfig(final Class<?>... classes) { this(Arrays.stream(classes).collect(Collectors.toSet())); }
Create a defensive resource configuration copy initialized with a given ResourceConfig.
Params:
  • original – resource configuration to createAndInitialize a defensive copy from.
/** * Create a defensive resource configuration copy initialized with a given {@code ResourceConfig}. * * @param original resource configuration to createAndInitialize a defensive copy from. */
public ResourceConfig(final ResourceConfig original) { this.state = new State(original.state); }
Add properties to ResourceConfig.

If any of the added properties exists already, old values of existing properties will be replaced by new values.
Params:
  • properties – properties to add.
Returns:updated resource configuration instance.
/** * Add properties to {@code ResourceConfig}. * <p/> * If any of the added properties exists already, old values of existing * properties will be replaced by new values. * * @param properties properties to add. * @return updated resource configuration instance. */
public final ResourceConfig addProperties(final Map<String, Object> properties) { state.addProperties(properties); return this; }
Set new configuration properties replacing all previously set properties.
Params:
  • properties – new set of configuration properties. The content of the map will replace any existing properties set on the configuration instance.
Returns:the updated configuration instance.
/** * Set new configuration properties replacing all previously set properties. * * @param properties new set of configuration properties. The content of * the map will replace any existing properties set on the configuration * instance. * @return the updated configuration instance. */
public ResourceConfig setProperties(final Map<String, ?> properties) { state.setProperties(properties); return this; } @Override public ResourceConfig property(final String name, final Object value) { state.property(name, value); return this; } @Override public ResourceConfig register(final Class<?> componentClass) { invalidateCache(); state.register(componentClass); return this; } @Override public ResourceConfig register(final Class<?> componentClass, final int bindingPriority) { invalidateCache(); state.register(componentClass, bindingPriority); return this; } @Override public ResourceConfig register(final Class<?> componentClass, final Class<?>... contracts) { invalidateCache(); state.register(componentClass, contracts); return this; } @Override public ResourceConfig register(final Class<?> componentClass, final Map<Class<?>, Integer> contracts) { invalidateCache(); state.register(componentClass, contracts); return this; } @Override public ResourceConfig register(final Object component) { invalidateCache(); state.register(component); return this; } @Override public ResourceConfig register(final Object component, final int bindingPriority) { invalidateCache(); state.register(component, bindingPriority); return this; } @Override public ResourceConfig register(final Object component, final Class<?>... contracts) { invalidateCache(); state.register(component, contracts); return this; } @Override public ResourceConfig register(final Object component, final Map<Class<?>, Integer> contracts) { invalidateCache(); state.register(component, contracts); return this; }
Register annotated JAX-RS resource, JAX-RS or Jersey contract provider or JAX-RS feature in the ResourceConfig.

Note that registered JAX-RS features are used to initialize and configure the Jersey runtime InjectionManager instance during application deployment, but are otherwise ignored by server-side runtime, unless they implement also another contract recognized by Jersey runtime.

Also note that registration of binder classes is note supported. Binders must be registered as instances.

Params:
  • classes – classes to register.
Returns:updated resource configuration instance.
/** * Register annotated JAX-RS resource, JAX-RS or Jersey contract provider or JAX-RS feature * in the {@code ResourceConfig}. * <p> * Note that registered JAX-RS features are used to initialize and configure * the Jersey runtime {@link InjectionManager} instance during application deployment, but are * otherwise ignored by server-side runtime, unless they implement also another contract * recognized by Jersey runtime. * </p> * <p> * Also note that registration of {@link Binder binder} classes is note supported. Binders * must be {@link #registerInstances(Object...) registered as instances}. * </p> * * @param classes classes to register. * @return updated resource configuration instance. */
public final ResourceConfig registerClasses(final Set<Class<?>> classes) { if (classes == null) { return this; } for (final Class<?> cls : classes) { register(cls); } return this; }
Register annotated JAX-RS resource, JAX-RS or Jersey contract provider or JAX-RS feature in the ResourceConfig.

Note that registered JAX-RS features are used to initialize and configure the Jersey runtime InjectionManager instance during application deployment, but are otherwise ignored by server-side runtime, unless they implement also another contract recognized by Jersey runtime.

Also note that registration of binder classes is note supported. Binders must be registered as instances.

Params:
  • classes – classes to register.
Returns:updated resource configuration instance.
/** * Register annotated JAX-RS resource, JAX-RS or Jersey contract provider or JAX-RS feature * in the {@code ResourceConfig}. * <p> * Note that registered JAX-RS features are used to initialize and configure * the Jersey runtime {@link InjectionManager} instance during application deployment, but are * otherwise ignored by server-side runtime, unless they implement also another contract * recognized by Jersey runtime. * </p> * <p> * Also note that registration of {@link Binder binder} classes is note supported. Binders * must be {@link #registerInstances(Object...) registered as instances}. * </p> * * @param classes classes to register. * @return updated resource configuration instance. */
public final ResourceConfig registerClasses(final Class<?>... classes) { if (classes == null) { return this; } return registerClasses(Arrays.stream(classes).collect(Collectors.toSet())); }
Register annotated JAX-RS resource, JAX-RS or Jersey contract provider, JAX-RS feature Jersey Binder instances (singletons) in the ResourceConfig.

Note that registered binders and JAX-RS features are used to initialize and configure the Jersey runtime InjectionManager instance during application deployment, but are otherwise ignored by server-side runtime, unless they implement also another contract recognized by Jersey runtime.

Params:
  • instances – instances to register.
Returns:updated resource configuration instance.
/** * Register annotated JAX-RS resource, JAX-RS or Jersey contract provider, JAX-RS feature * {@link Binder Jersey Binder} instances (singletons) in the {@code ResourceConfig}. * <p> * Note that registered binders and JAX-RS features are used to initialize and configure * the Jersey runtime {@link InjectionManager} instance during application deployment, but are * otherwise ignored by server-side runtime, unless they implement also another contract * recognized by Jersey runtime. * </p> * * @param instances instances to register. * @return updated resource configuration instance. */
public final ResourceConfig registerInstances(final Set<Object> instances) { if (instances == null) { return this; } for (final Object instance : instances) { register(instance); } return this; }
Register annotated JAX-RS resource, JAX-RS or Jersey contract provider, JAX-RS feature, Jersey Binder instances (singletons) in the ResourceConfig.

Note that registered binders and JAX-RS features are used to initialize and configure the Jersey runtime InjectionManager instance during application deployment, but are otherwise ignored by server-side runtime, unless they implement also another contract recognized by Jersey runtime.

Params:
  • instances – instances to register.
Returns:updated resource configuration instance.
/** * Register annotated JAX-RS resource, JAX-RS or Jersey contract provider, JAX-RS feature, * {@link Binder Jersey Binder} instances (singletons) in the {@code ResourceConfig}. * <p> * Note that registered binders and JAX-RS features are used to initialize and configure * the Jersey runtime {@link InjectionManager} instance during application deployment, but are * otherwise ignored by server-side runtime, unless they implement also another contract * recognized by Jersey runtime. * </p> * * @param instances instances to register. * @return updated resource configuration instance. */
public final ResourceConfig registerInstances(final Object... instances) { if (instances == null) { return this; } return registerInstances(Arrays.stream(instances).collect(Collectors.toSet())); }
Register new programmatic resource models in the ResourceConfig.
Params:
  • resources – resource models to register.
Returns:updated resource configuration instance.
/** * Register new programmatic resource models in the {@code ResourceConfig}. * * @param resources resource models to register. * @return updated resource configuration instance. */
public final ResourceConfig registerResources(final Resource... resources) { if (resources == null) { return this; } return registerResources(Arrays.stream(resources).collect(Collectors.toSet())); }
Register new resource models in the ResourceConfig.
Params:
  • resources – resource models to register.
Returns:updated resource configuration instance.
/** * Register new resource models in the {@code ResourceConfig}. * * @param resources resource models to register. * @return updated resource configuration instance. */
public final ResourceConfig registerResources(final Set<Resource> resources) { if (resources == null) { return this; } this.state.registerResources(resources); return this; }
Add a ResourceFinder to ResourceConfig.
Params:
Returns:updated resource configuration instance.
/** * Add a {@link ResourceFinder} to {@code ResourceConfig}. * * @param resourceFinder {@link ResourceFinder} * @return updated resource configuration instance. */
public final ResourceConfig registerFinder(final ResourceFinder resourceFinder) { if (resourceFinder == null) { return this; } invalidateCache(); this.state.registerFinder(resourceFinder); return this; }
Set the name of the application. The name is an arbitrary user defined name which is used to distinguish between Jersey applications in the case that more applications are deployed on the same runtime (container). The name can be used for example for purposes of monitoring by JMX when name identifies to which application deployed MBeans belong to. The name should be unique in the runtime.
Params:
  • applicationName – Unique application name.
Returns:updated resource configuration instance.
/** * Set the name of the application. The name is an arbitrary user defined name * which is used to distinguish between Jersey applications in the case that more applications * are deployed on the same runtime (container). The name can be used for example for purposes * of monitoring by JMX when name identifies to which application deployed MBeans belong to. * The name should be unique in the runtime. * * @param applicationName Unique application name. * @return updated resource configuration instance. */
public final ResourceConfig setApplicationName(final String applicationName) { state.setApplicationName(applicationName); return this; }
Set ClassLoader which will be used for resource discovery.
Params:
Returns:updated resource configuration instance.
/** * Set {@link ClassLoader} which will be used for resource discovery. * * @param classLoader provided {@link ClassLoader}. * @return updated resource configuration instance. */
public final ResourceConfig setClassLoader(final ClassLoader classLoader) { this.state.setClassLoader(classLoader); return this; }
Adds array of package names which will be used to scan for components.

Package scanning ignores inheritance and therefore Path annotation on parent classes and interfaces will be ignored.

Packages will be scanned recursively, including all nested packages.
Params:
  • packages – array of package names.
See Also:
Returns:updated resource configuration instance.
/** * Adds array of package names which will be used to scan for components. * <p/> * Package scanning ignores inheritance and therefore {@link Path} annotation * on parent classes and interfaces will be ignored. * <p/> * Packages will be scanned recursively, including all nested packages. * * @param packages array of package names. * @return updated resource configuration instance. * @see #packages(boolean, String...) */
public final ResourceConfig packages(final String... packages) { return packages(true, packages); }
Adds array of package names which will be used to scan for components.

Package scanning ignores an inheritance and therefore Path annotation on parent classes and interfaces will be ignored.

Params:
  • recursive – defines whether any nested packages in the collection of specified package names should be recursively scanned (value of true) as part of the package scanning or not (value of false).
  • packages – array of package names.
See Also:
Returns:updated resource configuration instance.
/** * Adds array of package names which will be used to scan for components. * <p/> * Package scanning ignores an inheritance and therefore {@link Path} annotation * on parent classes and interfaces will be ignored. * <p/> * @param recursive defines whether any nested packages in the collection of specified * package names should be recursively scanned (value of {@code true}) * as part of the package scanning or not (value of {@code false}). * @param packages array of package names. * @return updated resource configuration instance. * @see #packages(String...) */
public final ResourceConfig packages(final boolean recursive, final String... packages) { if (packages == null || packages.length == 0) { return this; } return registerFinder(new PackageNamesScanner(packages, recursive)); }
Adds array of package names which will be used to scan for components.

Package scanning ignores an inheritance and therefore Path annotation on parent classes and interfaces will be ignored.

Params:
  • recursive – defines whether any nested packages in the collection of specified package names should be recursively scanned (value of true) as part of the package scanning or not (value of false).
  • classLoader – defines the classloader used for scanning the packages and loading the classes.
  • packages – array of package names.
See Also:
Returns:updated resource configuration instance.
/** * Adds array of package names which will be used to scan for components. * <p/> * Package scanning ignores an inheritance and therefore {@link Path} annotation * on parent classes and interfaces will be ignored. * <p/> * @param recursive defines whether any nested packages in the collection of specified * package names should be recursively scanned (value of {@code true}) * as part of the package scanning or not (value of {@code false}). * @param classLoader defines the classloader used for scanning the packages and loading the classes. * @param packages array of package names. * @return updated resource configuration instance. * @see #packages(String...) */
public final ResourceConfig packages(final boolean recursive, final ClassLoader classLoader, final String... packages) { if (packages == null || packages.length == 0) { return this; } return registerFinder(new PackageNamesScanner(classLoader, packages, recursive)); }
Adds array of file and directory names to scan for components.

Any directories in the list will be scanned recursively, including their sub-directories.
Params:
  • files – array of file and directory names.
Returns:updated resource configuration instance.
/** * Adds array of file and directory names to scan for components. * <p/> * Any directories in the list will be scanned recursively, including their sub-directories. * * @param files array of file and directory names. * @return updated resource configuration instance. */
public final ResourceConfig files(final String... files) { return files(true, files); }
Adds array of file and directory names to scan for components.
Params:
  • recursive – defines whether any sub-directories of the directories specified in the collection of file names should be recursively scanned (value of true) as part of the file scanning or not (value of false).
  • files – array of file and directory names.
Returns:updated resource configuration instance.
/** * Adds array of file and directory names to scan for components. * * @param recursive defines whether any sub-directories of the directories specified * in the collection of file names should be recursively scanned (value of {@code true}) * as part of the file scanning or not (value of {@code false}). * @param files array of file and directory names. * @return updated resource configuration instance. */
public final ResourceConfig files(final boolean recursive, final String... files) { if (files == null || files.length == 0) { return this; } return registerFinder(new FilesScanner(files, recursive)); }
Invalidate cached component instances and classes.
/** * Invalidate cached component instances and classes. */
final void invalidateCache() { this.cachedClasses = null; this.cachedClassesView = null; this.cachedSingletons = null; this.cachedSingletonsView = null; // Reset ResourceFinders to make sure the next package scanning is successful. if (resetFinders) { for (final ResourceFinder finder : this.state.resourceFinders) { finder.reset(); } resetFinders = false; } }
Switches the ResourceConfig to read-only state.

Called by the WrappingResourceConfig if this ResourceConfig is set as the application. Also called by ApplicationHandler on WrappingResourceConfig at the point when it is going to build the resource model.

The method also sets the application name from properties if the name is not defined yer and the property ServerProperties.APPLICATION_NAME is defined.
/** * Switches the ResourceConfig to read-only state. * <p/> * Called by the WrappingResourceConfig if this ResourceConfig is set as the application. * Also called by ApplicationHandler on WrappingResourceConfig at the point when it is going * to build the resource model. * <p/> * The method also sets the application name from properties if the name is not defined yer * and the property {@link ServerProperties#APPLICATION_NAME} is defined. */
final void lock() { final State current = state; if (!(current instanceof ImmutableState)) { setupApplicationName(); ExternalPropertiesConfigurationFactory.configure(state); state = new ImmutableState(current); } } @Override public final ServerConfig getConfiguration() { return this; } @Override public final Map<String, Object> getProperties() { return state.getProperties(); } @Override public final Object getProperty(final String name) { return state.getProperty(name); } @Override public Collection<String> getPropertyNames() { return state.getPropertyNames(); } @Override public final boolean isProperty(final String name) { return state.isProperty(name); } @Override public final Set<Class<?>> getClasses() { if (cachedClassesView == null) { cachedClasses = _getClasses(); cachedClassesView = Collections.unmodifiableSet(cachedClasses); } return cachedClassesView; } @Override public final Set<Object> getInstances() { return getSingletons(); } @Override public final Set<Object> getSingletons() { if (cachedSingletonsView == null) { cachedSingletons = _getSingletons(); cachedSingletonsView = Collections.unmodifiableSet(cachedSingletons == null ? new HashSet<>() : cachedSingletons); } return cachedSingletonsView; }
Get the internal component bag.
Returns:internal component bag.
/** * Get the internal component bag. * * @return internal component bag. */
final ComponentBag getComponentBag() { return state.getComponentBag(); }
Configure auto-discoverables.
Params:
  • injectionManager – injection manager to obtain auto-discoverables from.
  • autoDiscoverables – list of registered auto discoverable components.
/** * Configure auto-discoverables. * * @param injectionManager injection manager to obtain auto-discoverables from. * @param autoDiscoverables list of registered auto discoverable components. */
final void configureAutoDiscoverableProviders(InjectionManager injectionManager, Collection<AutoDiscoverable> autoDiscoverables) { state.configureAutoDiscoverableProviders(injectionManager, autoDiscoverables, false); }
Configure forced auto-discoverables.
Params:
  • injectionManager – injection manager to obtain auto-discoverables from.
/** * Configure forced auto-discoverables. * * @param injectionManager injection manager to obtain auto-discoverables from. */
final void configureForcedAutoDiscoverableProviders(InjectionManager injectionManager) { state.configureAutoDiscoverableProviders(injectionManager, Collections.emptyList(), true); } final void configureMetaProviders(InjectionManager injectionManager, ManagedObjectsFinalizer finalizer) { state.configureMetaProviders(injectionManager, finalizer); } @Override public RuntimeType getRuntimeType() { return state.getRuntimeType(); } @Override public boolean isEnabled(final Feature feature) { return state.isEnabled(feature); } @Override public boolean isEnabled(final Class<? extends Feature> featureClass) { return state.isEnabled(featureClass); } @Override public boolean isRegistered(final Object component) { return state.isRegistered(component); } @Override public boolean isRegistered(final Class<?> componentClass) { return state.isRegistered(componentClass); } @Override public Map<Class<?>, Integer> getContracts(final Class<?> componentClass) { return state.getContracts(componentClass); }
Get configured resource and/or provider classes. The method is overridden in a private sub-type.
Returns:set of configured resource and/or provider classes.
/** * Get configured resource and/or provider classes. The method is overridden * in a {@link WrappingResourceConfig private sub-type}. * * @return set of configured resource and/or provider classes. */
Set<Class<?>> _getClasses() { final Set<Class<?>> result = scanClasses(); result.addAll(state.getClasses()); return result; } private Set<Class<?>> scanClasses() { final Set<Class<?>> result = new HashSet<>(); final ResourceConfig.State _state = state; final Set<ResourceFinder> rfs = new HashSet<>(_state.getResourceFinders()); // In case new entity is registered the available finders should be reset. resetFinders = true; // classes registered via configuration property final String[] classNames = parsePropertyValue(ServerProperties.PROVIDER_CLASSNAMES); if (classNames != null) { for (final String className : classNames) { try { result.add(_state.getClassLoader().loadClass(className)); } catch (final ClassNotFoundException e) { LOGGER.log(Level.CONFIG, LocalizationMessages.UNABLE_TO_LOAD_CLASS(className)); } } } final String[] packageNames = parsePropertyValue(ServerProperties.PROVIDER_PACKAGES); if (packageNames != null) { final Object p = getProperty(ServerProperties.PROVIDER_SCANNING_RECURSIVE); final boolean recursive = p == null || PropertiesHelper.isProperty(p); rfs.add(new PackageNamesScanner(packageNames, recursive)); } final String[] classPathElements = parsePropertyValue(ServerProperties.PROVIDER_CLASSPATH); if (classPathElements != null) { rfs.add(new FilesScanner(classPathElements, true)); } final AnnotationAcceptingListener parentAfl = AnnotationAcceptingListener.newJaxrsResourceAndProviderListener(_state.getClassLoader()); for (final ResourceFinder resourceFinder : rfs) { AnnotationAcceptingListener afl = parentAfl; if (resourceFinder instanceof PackageNamesScanner) { final ClassLoader classLoader = ((PackageNamesScanner) resourceFinder).getClassloader(); if (!getClassLoader().equals(classLoader)) { afl = AnnotationAcceptingListener.newJaxrsResourceAndProviderListener(classLoader); } } while (resourceFinder.hasNext()) { final String next = resourceFinder.next(); if (afl.accept(next)) { final InputStream in = resourceFinder.open(); try { afl.process(next, in); } catch (final IOException e) { LOGGER.log(Level.WARNING, LocalizationMessages.RESOURCE_CONFIG_UNABLE_TO_PROCESS(next)); } finally { try { in.close(); } catch (final IOException ex) { LOGGER.log(Level.FINER, "Error closing resource stream.", ex); } } } } if (afl != parentAfl) { result.addAll(afl.getAnnotatedClasses()); } } result.addAll(parentAfl.getAnnotatedClasses()); return result; } private String[] parsePropertyValue(final String propertyName) { String[] classNames = null; final Object o = state.getProperties().get(propertyName); if (o != null) { if (o instanceof String) { classNames = Tokenizer.tokenize((String) o); } else if (o instanceof String[]) { classNames = Tokenizer.tokenize((String[]) o); } } return classNames; }
Return classes which were registered by the user and not found by class path scanning (or any other scanning).
Returns:Set of classes registered by the user.
/** * Return classes which were registered by the user and not found by class path scanning (or any other scanning). * * @return Set of classes registered by the user. */
Set<Class<?>> getRegisteredClasses() { return state.getComponentBag().getRegistrations(); }
Get configured resource and/or provider instances. The method is overridden in a private sub-type.
Returns:set of configured resource and/or provider instances.
/** * Get configured resource and/or provider instances. The method is overridden * in a {@link WrappingResourceConfig private sub-type}. * * @return set of configured resource and/or provider instances. */
Set<Object> _getSingletons() { final Set<Object> result = new HashSet<>(); result.addAll(state.getInstances()); return result; } @Override public final Set<Resource> getResources() { return state.getResources(); }
Get resource and provider class loader.
Returns:class loader to be used when looking up the resource classes and providers.
/** * Get resource and provider class loader. * * @return class loader to be used when looking up the resource classes and * providers. */
public final ClassLoader getClassLoader() { return state.getClassLoader(); }
Returns JAX-RS application corresponding with this ResourceConfig.
Returns:JAX-RS application corresponding with this ResourceConfig.
/** * Returns JAX-RS application corresponding with this ResourceConfig. * * @return JAX-RS application corresponding with this ResourceConfig. */
public final Application getApplication() { return _getApplication(); }
Allows overriding the getApplication() method functionality in WrappingResourceConfig.
Returns:JAX-RS application corresponding with this ResourceConfig.
/** * Allows overriding the {@link #getApplication()} method functionality in {@link WrappingResourceConfig}. * * @return JAX-RS application corresponding with this ResourceConfig. */
Application _getApplication() { return this; }
Get the name of the Jersey application.
See Also:
Returns:Name of the application.
/** * Get the name of the Jersey application. * * @return Name of the application. * @see #setApplicationName(String) */
public String getApplicationName() { return state.getApplicationName(); }
Method used by ApplicationHandler to retrieve application class (this method is overridden by WrappingResourceConfig).
Returns:application class
/** * Method used by ApplicationHandler to retrieve application class * (this method is overridden by {@link WrappingResourceConfig}). * * @return application class */
Class<? extends Application> getApplicationClass() { return null; }
This method is used by ApplicationHandler to set application instance to the resource config (should always be called on WrappingResourceConfig instance, never on plain instances of ResourceConfig unless we have a bug in the code).
Params:
  • app – JAX-RS application
Returns:this ResourceConfig instance (for convenience)
/** * This method is used by ApplicationHandler to set application instance to the resource config (should * always be called on WrappingResourceConfig instance, never on plain instances of ResourceConfig * unless we have a bug in the code). * * @param app JAX-RS application * @return this ResourceConfig instance (for convenience) */
final ResourceConfig setApplication(final Application app) { return _setApplication(app); }
Allows overriding the setApplication() method functionality in WrappingResourceConfig.
Params:
  • app – application to be set for this ResourceConfig
Returns:this resource config instance
/** * Allows overriding the setApplication() method functionality in WrappingResourceConfig. * * @param app application to be set for this ResourceConfig * @return this resource config instance */
ResourceConfig _setApplication(final Application app) { throw new UnsupportedOperationException(); } private static class WrappingResourceConfig extends ResourceConfig { private Application application; private Class<? extends Application> applicationClass; private final Set<Class<?>> defaultClasses = new HashSet<>(); public WrappingResourceConfig( final Application application, final Class<? extends Application> applicationClass, final Set<Class<?>> defaultClasses) { if (application == null && applicationClass == null) { throw new IllegalArgumentException(LocalizationMessages.RESOURCE_CONFIG_ERROR_NULL_APPLICATIONCLASS()); } this.application = application; this.applicationClass = applicationClass; if (defaultClasses != null) { this.defaultClasses.addAll(defaultClasses); } mergeApplications(application); }
Set the JAX-RS Application instance in the ResourceConfig.

This method is used by the ApplicationHandler in case this resource configuration instance was created with application class rather than application instance.
Params:
  • application – JAX-RS Application instance.
Returns:updated resource configuration instance.
/** * Set the {@link javax.ws.rs.core.Application JAX-RS Application instance} * in the {@code ResourceConfig}. * <p/> * This method is used by the {@link org.glassfish.jersey.server.ApplicationHandler} in case this resource * configuration instance was created with application class rather than application instance. * * @param application JAX-RS Application instance. * @return updated resource configuration instance. */
@Override ResourceConfig _setApplication(final Application application) { this.application = application; this.applicationClass = null; mergeApplications(application); return this; }
Get the original underlying JAX-RS Application instance used to initialize the resource configuration instance.
Returns:JAX-RS application instance.
/** * Get the original underlying JAX-RS {@link Application} instance used to * initialize the resource configuration instance. * * @return JAX-RS application instance. */
@Override Application _getApplication() { return application; }
Get the original JAX-RS Application class provided it was not instantiated yet. A null is returned in case the class has been instantiated already or was not configured at all.

This class will be used to initialize the resource configuration instance. If there is no JAX-RS application class set, or if the class has been instantiated already, the method will return null.

Returns:original JAX-RS application class or null if there is no such class configured or if the class has been already instantiated.
/** * Get the original JAX-RS {@link Application} class provided it was not * instantiated yet. A {@code null} is returned in case the class has been * instantiated already or was not configured at all. * <p> * This class will be used to initialize the resource configuration instance. * If there is no JAX-RS application class set, or if the class has been * instantiated already, the method will return {@code null}. * </p> * * @return original JAX-RS application class or {@code null} if there is no * such class configured or if the class has been already instantiated. */
@Override Class<? extends Application> getApplicationClass() { return applicationClass; }
Merges fields (e.g. custom binders, properties) of the given application with this application.

The merging should be done because of the possibility of reloading this ResourceConfig in a container so this resource config should know about custom binders and properties of the underlying application to ensure the reload process will complete successfully.

Params:
  • application – the application which fields should be merged with this application.
See Also:
/** * Merges fields (e.g. custom binders, properties) of the given application with this application. * <p> * The merging should be done because of the possibility of reloading this {@code ResourceConfig} in a container * so this resource config should know about custom binders and properties of the underlying application to ensure * the reload process will complete successfully. * </p> * * @param application the application which fields should be merged with this application. * @see org.glassfish.jersey.server.spi.Container#reload() * @see org.glassfish.jersey.server.spi.Container#reload(ResourceConfig) */
private void mergeApplications(final Application application) { if (application instanceof ResourceConfig) { // Merge custom binders. final ResourceConfig rc = (ResourceConfig) application; // Merge resources super.registerResources(rc.getResources()); // properties set on the wrapping resource config take precedence // (as those are retrieved from the web.xml, for example) rc.invalidateCache(); rc.addProperties(super.getProperties()); super.addProperties(rc.getProperties()); super.setApplicationName(rc.getApplicationName()); super.setClassLoader(rc.getClassLoader()); rc.lock(); } else if (application != null) { super.addProperties(application.getProperties()); } } @Override Set<Class<?>> _getClasses() { final Set<Class<?>> result = new HashSet<>(); final Set<Class<?>> applicationClasses = application.getClasses(); result.addAll(applicationClasses == null ? new HashSet<Class<?>>() : applicationClasses); if (result.isEmpty() && getSingletons().isEmpty()) { result.addAll(defaultClasses); } // if the application is not an instance of ResourceConfig, handle scanning triggered via properties if (!(application instanceof ResourceConfig)) { result.addAll(super._getClasses()); } return result; } @Override Set<Object> _getSingletons() { return application.getSingletons(); } }
Create runtime configuration initialized from a given deploy-time JAX-RS/Jersey application configuration.
Params:
  • application – deploy-time JAX-RS/Jersey application configuration.
Returns:initialized run-time resource config.
/** * Create runtime configuration initialized from a given deploy-time JAX-RS/Jersey * application configuration. * * @param application deploy-time JAX-RS/Jersey application configuration. * @return initialized run-time resource config. */
static ResourceConfig createRuntimeConfig(final Application application) { return (application instanceof ResourceConfig) ? new RuntimeConfig((ResourceConfig) application) : new RuntimeConfig(application); } private static class RuntimeConfig extends ResourceConfig { private final Set<Class<?>> originalRegistrations; private final Application application; private RuntimeConfig(final ResourceConfig original) { super(original); this.application = original; final Application customRootApp = ResourceConfig.unwrapCustomRootApplication(original); if (customRootApp != null) { registerComponentsOf(customRootApp); } originalRegistrations = Collections.newSetFromMap(new IdentityHashMap<>()); originalRegistrations.addAll(super.getRegisteredClasses()); // Register externally provided instances. final Set<Object> externalInstances = original.getSingletons().stream() .filter(external -> !originalRegistrations.contains(external.getClass())) .collect(Collectors.toSet()); registerInstances(externalInstances); // Register externally provided classes. final Set<Class<?>> externalClasses = original.getClasses().stream() .filter(external -> !originalRegistrations.contains(external)) .collect(Collectors.toSet()); registerClasses(externalClasses); } private void registerComponentsOf(final Application application) { Errors.processWithException(new Runnable() { @Override public void run() { // First register instances that should take precedence over classes // in case of duplicate registrations final Set<Object> singletons = application.getSingletons(); if (singletons != null) { registerInstances( singletons.stream() .filter(input -> { if (input == null) { Errors.warning(application, LocalizationMessages.NON_INSTANTIABLE_COMPONENT(null)); } return input != null; }) .collect(Collectors.toSet())); } final Set<Class<?>> classes = application.getClasses(); if (classes != null) { registerClasses(classes.stream() .filter(input -> { if (input == null) { Errors.warning(application, LocalizationMessages.NON_INSTANTIABLE_COMPONENT(null)); } return input != null; }) .collect(Collectors.toSet())); } } }); } private RuntimeConfig(final Application application) { super(); this.application = application; if (application != null) { registerComponentsOf(application); // Copy all available properties. addProperties(application.getProperties()); } originalRegistrations = super.getRegisteredClasses(); } @Override Set<Class<?>> _getClasses() { // Get only a read-only classes cached in internal state. return super.state.getClasses(); } @Override Set<Object> _getSingletons() { // Get only a read-only classes cached in internal state. return super.state.getInstances(); } @Override Set<Class<?>> getRegisteredClasses() { return originalRegistrations; } @Override Application _getApplication() { return application; } } private static Application unwrapCustomRootApplication(ResourceConfig resourceConfig) { Application app = null; while (resourceConfig != null) { app = resourceConfig.getApplication(); if (app == resourceConfig) { // resource config is the root application - return null return null; } else if (app instanceof ResourceConfig) { resourceConfig = (ResourceConfig) app; } else { break; } } return app; }
Get the most internal wrapped application class.

This method is similar to getApplication() except if provided application was created by wrapping multiple ResourceConfig instances, this method will return the original (inner-most) JAX-RS Application sub-class rather than a potentially intermediate ResourceConfig wrapper.

Params:
  • application – application that is potentially wrapped.
Returns:the original, inner-most Application subclass. May return the same instance directly, in case the supplied application instance is not a wrapper ResourceConfig instance.
/** * Get the most internal wrapped {@link Application application} class. * <p> * This method is similar to {@link ResourceConfig#getApplication()} except if provided application was * created by wrapping multiple {@code ResourceConfig} instances, this method will return the original (inner-most) * JAX-RS {@code Application} sub-class rather than a potentially intermediate {@code ResourceConfig} wrapper. * </p> * * @param application application that is potentially wrapped. * @return the original, inner-most {@link Application} subclass. May return the same instance directly, * in case the supplied {@code application} instance is not a wrapper {@code ResourceConfig} instance. */
static Application unwrapApplication(Application application) { while (application instanceof ResourceConfig) { final Application wrappedApplication = ((ResourceConfig) application).getApplication(); if (wrappedApplication == application) { break; } application = wrappedApplication; } return application; } private void setupApplicationName() { final String appName = ServerProperties.getValue(getProperties(), ServerProperties.APPLICATION_NAME, null, String.class); if (appName != null && getApplicationName() == null) { setApplicationName(appName); } } }