/*
* Copyright 2015-2019 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v20.html
*/
package org.junit.jupiter.api.extension;
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
import static org.apiguardian.api.API.Status.STABLE;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import org.apiguardian.api.API;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.platform.commons.support.ReflectionSupport;
import org.junit.platform.commons.util.PreconditionViolationException;
import org.junit.platform.commons.util.Preconditions;
ExtensionContext
encapsulates the context in which the
current test or container is being executed.
Extensions
are provided an instance of ExtensionContext
to perform their work.
See Also: Since: 5.0
/**
* {@code ExtensionContext} encapsulates the <em>context</em> in which the
* current test or container is being executed.
*
* <p>{@link Extension Extensions} are provided an instance of
* {@code ExtensionContext} to perform their work.
*
* @since 5.0
* @see Store
* @see Namespace
*/
@API(status = STABLE, since = "5.0")
public interface ExtensionContext {
Get the parent extension context, if available.
See Also: Returns: an Optional
containing the parent; never null
but potentially empty
/**
* Get the parent extension context, if available.
*
* @return an {@code Optional} containing the parent; never {@code null} but
* potentially empty
* @see #getRoot()
*/
Optional<ExtensionContext> getParent();
Get the root ExtensionContext
. See Also: Returns: the root extension context; never null
but potentially this ExtensionContext
/**
* Get the <em>root</em> {@code ExtensionContext}.
*
* @return the root extension context; never {@code null} but potentially
* <em>this</em> {@code ExtensionContext}
* @see #getParent()
*/
ExtensionContext getRoot();
Get the unique ID of the current test or container.
Returns: the unique ID of the test or container; never null
or blank
/**
* Get the unique ID of the current test or container.
*
* @return the unique ID of the test or container; never {@code null} or blank
*/
String getUniqueId();
Get the display name for the current test or container.
The display name is either a default name or a custom name configured via @DisplayName
.
For details on default display names consult the Javadoc for TestInfo.getDisplayName()
.
Note that display names are typically used for test reporting in IDEs
and build tools and may contain spaces, special characters, and even emoji.
Returns: the display name of the test or container; never null
or blank
/**
* Get the display name for the current test or container.
*
* <p>The display name is either a default name or a custom name configured
* via {@link org.junit.jupiter.api.DisplayName @DisplayName}.
*
* <p>For details on default display names consult the Javadoc for
* {@link org.junit.jupiter.api.TestInfo#getDisplayName()}.
*
* <p>Note that display names are typically used for test reporting in IDEs
* and build tools and may contain spaces, special characters, and even emoji.
*
* @return the display name of the test or container; never {@code null} or blank
*/
String getDisplayName();
Get the set of all tags for the current test or container.
Tags may be declared directly on the test element or inherited
from an outer context.
Returns: the set of tags for the test or container; never null
but potentially empty
/**
* Get the set of all tags for the current test or container.
*
* <p>Tags may be declared directly on the test element or <em>inherited</em>
* from an outer context.
*
* @return the set of tags for the test or container; never {@code null} but
* potentially empty
*/
Set<String> getTags();
Get the AnnotatedElement
corresponding to the current extension context, if available. For example, if the current extension context encapsulates a test class, test method, test factory method, or test template method, the annotated element will be the corresponding Class
or Method
reference.
Favor this method over more specific methods whenever the AnnotatedElement
API suits the task at hand — for example, when looking up annotations regardless of concrete element type.
See Also: Returns: an Optional
containing the AnnotatedElement
; never null
but potentially empty
/**
* Get the {@link AnnotatedElement} corresponding to the current extension
* context, if available.
*
* <p>For example, if the current extension context encapsulates a test
* class, test method, test factory method, or test template method, the
* annotated element will be the corresponding {@link Class} or {@link Method}
* reference.
*
* <p>Favor this method over more specific methods whenever the
* {@code AnnotatedElement} API suits the task at hand — for example,
* when looking up annotations regardless of concrete element type.
*
* @return an {@code Optional} containing the {@code AnnotatedElement};
* never {@code null} but potentially empty
* @see #getTestClass()
* @see #getTestMethod()
*/
Optional<AnnotatedElement> getElement();
Get the Class
associated with the current test or container, if available. See Also: Returns: an Optional
containing the class; never null
but potentially empty
/**
* Get the {@link Class} associated with the current test or container,
* if available.
*
* @return an {@code Optional} containing the class; never {@code null} but
* potentially empty
* @see #getRequiredTestClass()
*/
Optional<Class<?>> getTestClass();
Get the required Class
associated with the current test or container. Use this method as an alternative to getTestClass()
for use cases in which the test class is required to be present.
Throws: - PreconditionViolationException – if the test class is not present in this
ExtensionContext
Returns: the test class; never null
/**
* Get the <em>required</em> {@link Class} associated with the current test
* or container.
*
* <p>Use this method as an alternative to {@link #getTestClass()} for use
* cases in which the test class is required to be present.
*
* @return the test class; never {@code null}
* @throws PreconditionViolationException if the test class is not present
* in this {@code ExtensionContext}
*/
default Class<?> getRequiredTestClass() {
return Preconditions.notNull(getTestClass().orElse(null),
"Illegal state: required test class is not present in the current ExtensionContext");
}
Get the Lifecycle
of the test
instance associated with the current test or container, if available. See Also: Returns: an Optional
containing the test instance Lifecycle
; never null
but potentially empty Since: 5.1
/**
* Get the {@link Lifecycle} of the {@linkplain #getTestInstance() test
* instance} associated with the current test or container, if available.
*
* @return an {@code Optional} containing the test instance {@code Lifecycle};
* never {@code null} but potentially empty
* @see org.junit.jupiter.api.TestInstance {@code @TestInstance}
* @since 5.1
*/
@API(status = STABLE, since = "5.1")
Optional<Lifecycle> getTestInstanceLifecycle();
Get the test instance associated with the current test or container,
if available.
See Also: Returns: an Optional
containing the test instance; never null
but potentially empty
/**
* Get the test instance associated with the current test or container,
* if available.
*
* @return an {@code Optional} containing the test instance; never
* {@code null} but potentially empty
* @see #getRequiredTestInstance()
* @see #getTestInstances()
*/
Optional<Object> getTestInstance();
Get the required test instance associated with the current test
or container.
Use this method as an alternative to getTestInstance()
for use cases in which the test instance is required to be present.
Throws: - PreconditionViolationException – if the test instance is not present in this
ExtensionContext
See Also: Returns: the test instance; never null
/**
* Get the <em>required</em> test instance associated with the current test
* or container.
*
* <p>Use this method as an alternative to {@link #getTestInstance()} for use
* cases in which the test instance is required to be present.
*
* @return the test instance; never {@code null}
* @throws PreconditionViolationException if the test instance is not present
* in this {@code ExtensionContext}
*
* @see #getRequiredTestInstances()
*/
default Object getRequiredTestInstance() {
return Preconditions.notNull(getTestInstance().orElse(null),
"Illegal state: required test instance is not present in the current ExtensionContext");
}
Get the test instances associated with the current test or container,
if available.
While top-level tests only have a single test instance, nested tests
have one additional instance for each enclosing test class.
See Also: Returns: an Optional
containing the test instances; never null
but potentially empty Since: 5.4
/**
* Get the test instances associated with the current test or container,
* if available.
*
* <p>While top-level tests only have a single test instance, nested tests
* have one additional instance for each enclosing test class.
*
* @return an {@code Optional} containing the test instances; never
* {@code null} but potentially empty
* @see #getRequiredTestInstances()
*
* @since 5.4
*/
@API(status = EXPERIMENTAL, since = "5.4")
Optional<TestInstances> getTestInstances();
Get the required test instances associated with the current test
or container.
Use this method as an alternative to getTestInstances()
for use cases in which the test instances are required to be present.
Throws: - PreconditionViolationException – if the test instances are not present in this
ExtensionContext
Returns: the test instances; never null
Since: 5.4
/**
* Get the <em>required</em> test instances associated with the current test
* or container.
*
* <p>Use this method as an alternative to {@link #getTestInstances()} for use
* cases in which the test instances are required to be present.
*
* @return the test instances; never {@code null}
* @throws PreconditionViolationException if the test instances are not present
* in this {@code ExtensionContext}
*
* @since 5.4
*/
@API(status = EXPERIMENTAL, since = "5.4")
default TestInstances getRequiredTestInstances() {
return Preconditions.notNull(getTestInstances().orElse(null),
"Illegal state: required test instances are not present in the current ExtensionContext");
}
Get the Method
associated with the current test, if available. See Also: Returns: an Optional
containing the method; never null
but potentially empty
/**
* Get the {@link Method} associated with the current test, if available.
*
* @return an {@code Optional} containing the method; never {@code null} but
* potentially empty
* @see #getRequiredTestMethod()
*/
Optional<Method> getTestMethod();
Get the required Method
associated with the current test or container. Use this method as an alternative to getTestMethod()
for use cases in which the test method is required to be present.
Throws: - PreconditionViolationException – if the test method is not present in this
ExtensionContext
Returns: the test method; never null
/**
* Get the <em>required</em> {@link Method} associated with the current test
* or container.
*
* <p>Use this method as an alternative to {@link #getTestMethod()} for use
* cases in which the test method is required to be present.
*
* @return the test method; never {@code null}
* @throws PreconditionViolationException if the test method is not present
* in this {@code ExtensionContext}
*/
default Method getRequiredTestMethod() {
return Preconditions.notNull(getTestMethod().orElse(null),
"Illegal state: required test method is not present in the current ExtensionContext");
}
Get the exception that was thrown during execution of the test or container associated with this ExtensionContext
, if available. This method is typically used for logging and tracing purposes. If you
wish to actually handle an exception thrown during test execution, implement the TestExecutionExceptionHandler
API.
Unlike the exception passed to a TestExecutionExceptionHandler
, an execution exception returned by this method can be any exception thrown during the invocation of a @Test
method, its surrounding @BeforeEach
and @AfterEach
methods, or a test-level Extension
. Similarly, if this ExtensionContext
represents a test class, the execution exception returned by this method can be any exception thrown in a @BeforeAll
or AfterAll
method or a class-level Extension
.
Note, however, that this method will never return an exception swallowed by a TestExecutionExceptionHandler
. Furthermore, if multiple exceptions have been thrown during test execution, the exception returned by this method will be the first such exception with all additional exceptions
suppressed in the first one.
Returns: an Optional
containing the exception thrown; never null
but potentially empty if test execution has not (yet) resulted in an exception
/**
* Get the exception that was thrown during execution of the test or container
* associated with this {@code ExtensionContext}, if available.
*
* <p>This method is typically used for logging and tracing purposes. If you
* wish to actually <em>handle</em> an exception thrown during test execution,
* implement the {@link TestExecutionExceptionHandler} API.
*
* <p>Unlike the exception passed to a {@code TestExecutionExceptionHandler},
* an <em>execution exception</em> returned by this method can be any
* exception thrown during the invocation of a {@code @Test} method, its
* surrounding {@code @BeforeEach} and {@code @AfterEach} methods, or a
* test-level {@link Extension}. Similarly, if this {@code ExtensionContext}
* represents a test class, the <em>execution exception</em> returned by
* this method can be any exception thrown in a {@code @BeforeAll} or
* {@code AfterAll} method or a class-level {@link Extension}.
*
* <p>Note, however, that this method will never return an exception
* swallowed by a {@code TestExecutionExceptionHandler}. Furthermore, if
* multiple exceptions have been thrown during test execution, the exception
* returned by this method will be the first such exception with all
* additional exceptions {@linkplain Throwable#addSuppressed(Throwable)
* suppressed} in the first one.
*
* @return an {@code Optional} containing the exception thrown; never
* {@code null} but potentially empty if test execution has not (yet)
* resulted in an exception
*/
Optional<Throwable> getExecutionException();
Get the configuration parameter stored under the specified key
. If no such key is present in the ConfigurationParameters
for the JUnit Platform, an attempt will be made to look up the value as a JVM system property. If no such system property exists, an attempt will be made to look up the value in the JUnit Platform properties file.
Params: - key – the key to look up; never
null
or blank
See Also: - System.getProperty(String)
- ConfigurationParameters
Returns: an Optional
containing the value; never null
but potentially empty Since: 5.1
/**
* Get the configuration parameter stored under the specified {@code key}.
*
* <p>If no such key is present in the {@code ConfigurationParameters} for
* the JUnit Platform, an attempt will be made to look up the value as a
* JVM system property. If no such system property exists, an attempt will
* be made to look up the value in the JUnit Platform properties file.
*
* @param key the key to look up; never {@code null} or blank
* @return an {@code Optional} containing the value; never {@code null}
* but potentially empty
*
* @see System#getProperty(String)
* @see org.junit.platform.engine.ConfigurationParameters
* @since 5.1
*/
@API(status = STABLE, since = "5.1")
Optional<String> getConfigurationParameter(String key);
Publish a map of key-value pairs to be consumed by an org.junit.platform.engine.EngineExecutionListener
in order to supply additional information to the reporting infrastructure. Params: - map – the key-value pairs to be published; never
null
; keys and values within entries in the map also must not be null
or blank
See Also: - publishReportEntry(String, String)
- publishReportEntry(String)
- reportingEntryPublished.reportingEntryPublished
/**
* Publish a map of key-value pairs to be consumed by an
* {@code org.junit.platform.engine.EngineExecutionListener} in order to
* supply additional information to the reporting infrastructure.
*
* @param map the key-value pairs to be published; never {@code null};
* keys and values within entries in the map also must not be
* {@code null} or blank
* @see #publishReportEntry(String, String)
* @see #publishReportEntry(String)
* @see org.junit.platform.engine.EngineExecutionListener#reportingEntryPublished
*/
void publishReportEntry(Map<String, String> map);
Publish the specified key-value pair to be consumed by an org.junit.platform.engine.EngineExecutionListener
in order to supply additional information to the reporting infrastructure. Params: - key – the key of the published pair; never
null
or blank - value – the value of the published pair; never
null
or blank
See Also: - publishReportEntry(Map<String,String>)
- publishReportEntry(String)
- reportingEntryPublished.reportingEntryPublished
/**
* Publish the specified key-value pair to be consumed by an
* {@code org.junit.platform.engine.EngineExecutionListener} in order to
* supply additional information to the reporting infrastructure.
*
* @param key the key of the published pair; never {@code null} or blank
* @param value the value of the published pair; never {@code null} or blank
* @see #publishReportEntry(Map)
* @see #publishReportEntry(String)
* @see org.junit.platform.engine.EngineExecutionListener#reportingEntryPublished
*/
default void publishReportEntry(String key, String value) {
this.publishReportEntry(Collections.singletonMap(key, value));
}
Publish the specified value to be consumed by an org.junit.platform.engine.EngineExecutionListener
in order to supply additional information to the reporting infrastructure. This method delegates to publishReportEntry(String, String)
, supplying "value"
as the key and the supplied value
argument as the value.
Params: - value – the value to be published; never
null
or blank
See Also: - publishReportEntry(Map<String,String>)
- publishReportEntry(String, String)
- reportingEntryPublished.reportingEntryPublished
Since: 5.3
/**
* Publish the specified value to be consumed by an
* {@code org.junit.platform.engine.EngineExecutionListener} in order to
* supply additional information to the reporting infrastructure.
*
* <p>This method delegates to {@link #publishReportEntry(String, String)},
* supplying {@code "value"} as the key and the supplied {@code value}
* argument as the value.
*
* @param value the value to be published; never {@code null} or blank
* @see #publishReportEntry(Map)
* @see #publishReportEntry(String, String)
* @see org.junit.platform.engine.EngineExecutionListener#reportingEntryPublished
* @since 5.3
*/
@API(status = STABLE, since = "5.3")
default void publishReportEntry(String value) {
this.publishReportEntry("value", value);
}
Get the Store
for the supplied Namespace
. Use getStore(Namespace.GLOBAL)
to get the default, global Namespace
.
A store is bound to its extension context lifecycle. When an extension context lifecycle ends it closes its associated store. All stored values that are instances of CloseableResource
are notified by invoking their close()
methods.
Params: - namespace – the
Namespace
to get the store for; never null
See Also: Returns: the store in which to put and get objects for other invocations working in the same namespace; never null
/**
* Get the {@link Store} for the supplied {@link Namespace}.
*
* <p>Use {@code getStore(Namespace.GLOBAL)} to get the default, global {@link Namespace}.
*
* <p>A store is bound to its extension context lifecycle. When an extension
* context lifecycle ends it closes its associated store. All stored values
* that are instances of {@link ExtensionContext.Store.CloseableResource} are
* notified by invoking their {@code close()} methods.
*
* @param namespace the {@code Namespace} to get the store for; never {@code null}
* @return the store in which to put and get objects for other invocations
* working in the same namespace; never {@code null}
* @see Namespace#GLOBAL
*/
Store getStore(Namespace namespace);
Store
provides methods for extensions to save and retrieve data. /**
* {@code Store} provides methods for extensions to save and retrieve data.
*/
interface Store {
Classes implementing this interface indicate that they want to close
some underlying resource or resources when the enclosing Store
is closed. Note that the CloseableResource
API is only honored for objects stored within an extension context Store
.
Since: 5.1
/**
* Classes implementing this interface indicate that they want to {@link #close}
* some underlying resource or resources when the enclosing {@link Store Store}
* is closed.
*
* <p>Note that the {@code CloseableResource} API is only honored for
* objects stored within an extension context {@link Store Store}.
*
* @since 5.1
*/
@API(status = STABLE, since = "5.1")
interface CloseableResource {
Close underlying resources.
Throws: - Throwable – any throwable will be caught and rethrown
/**
* Close underlying resources.
*
* @throws Throwable any throwable will be caught and rethrown
*/
void close() throws Throwable;
}
Get the value that is stored under the supplied key
. If no value is stored in the current ExtensionContext
for the supplied key
, ancestors of the context will be queried for a value with the same key
in the Namespace
used to create this store.
For greater type safety, consider using get(Object, Class<Object>)
instead.
Params: - key – the key; never
null
See Also: Returns: the value; potentially null
/**
* Get the value that is stored under the supplied {@code key}.
*
* <p>If no value is stored in the current {@link ExtensionContext}
* for the supplied {@code key}, ancestors of the context will be queried
* for a value with the same {@code key} in the {@code Namespace} used
* to create this store.
*
* <p>For greater type safety, consider using {@link #get(Object, Class)}
* instead.
*
* @param key the key; never {@code null}
* @return the value; potentially {@code null}
* @see #get(Object, Class)
*/
Object get(Object key);
Get the value of the specified required type that is stored under the supplied key
. If no value is stored in the current ExtensionContext
for the supplied key
, ancestors of the context will be queried for a value with the same key
in the Namespace
used to create this store.
Params: - key – the key; never
null
- requiredType – the required type of the value; never
null
Type parameters: - <V> – the value type
See Also: Returns: the value; potentially null
/**
* Get the value of the specified required type that is stored under
* the supplied {@code key}.
*
* <p>If no value is stored in the current {@link ExtensionContext}
* for the supplied {@code key}, ancestors of the context will be queried
* for a value with the same {@code key} in the {@code Namespace} used
* to create this store.
*
* @param key the key; never {@code null}
* @param requiredType the required type of the value; never {@code null}
* @param <V> the value type
* @return the value; potentially {@code null}
* @see #get(Object)
*/
<V> V get(Object key, Class<V> requiredType);
Get the object of type type
that is present in this Store
(keyed by type
); and otherwise invoke the default constructor for type
to generate the object, store it, and return it. This method is a shortcut for the following, where X
is the type of object we wish to retrieve from the store.
X x = store.getOrComputeIfAbsent(X.class, key -> new X(), X.class);
// Equivalent to:
// X x = store.getOrComputeIfAbsent(X.class);
See getOrComputeIfAbsent(Object, Function<Object,Object>, Class<Object>)
for further details.
If type
implements CloseableResource
the close()
method will be invoked on the stored object when the store is closed.
Params: - type – the type of object to retrieve; never
null
Type parameters: - <V> – the key and value type
See Also: Returns: the object; never null
Since: 5.1
/**
* Get the object of type {@code type} that is present in this
* {@code Store} (<em>keyed</em> by {@code type}); and otherwise invoke
* the default constructor for {@code type} to generate the object,
* store it, and return it.
*
* <p>This method is a shortcut for the following, where {@code X} is
* the type of object we wish to retrieve from the store.
*
* <pre style="code">
* X x = store.getOrComputeIfAbsent(X.class, key -> new X(), X.class);
* // Equivalent to:
* // X x = store.getOrComputeIfAbsent(X.class);
* </pre>
*
* <p>See {@link #getOrComputeIfAbsent(Object, Function, Class)} for
* further details.
*
* <p>If {@code type} implements {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
*
* @param type the type of object to retrieve; never {@code null}
* @param <V> the key and value type
* @return the object; never {@code null}
* @see #getOrComputeIfAbsent(Object, Function)
* @see #getOrComputeIfAbsent(Object, Function, Class)
* @see CloseableResource
* @since 5.1
*/
@API(status = STABLE, since = "5.1")
default <V> V getOrComputeIfAbsent(Class<V> type) {
return getOrComputeIfAbsent(type, ReflectionSupport::newInstance, type);
}
Get the value that is stored under the supplied key
. If no value is stored in the current ExtensionContext
for the supplied key
, ancestors of the context will be queried for a value with the same key
in the Namespace
used to create this store. If no value is found for the supplied key
, a new value will be computed by the defaultCreator
(given the key
as input), stored, and returned.
For greater type safety, consider using getOrComputeIfAbsent(Object, Function<Object,Object>, Class<Object>)
instead.
If the created value is an instance of CloseableResource
the close()
method will be invoked on the stored object when the store is closed.
Params: - key – the key; never
null
- defaultCreator – the function called with the supplied
key
to create a new value; never null
Type parameters: See Also: Returns: the value; potentially null
/**
* Get the value that is stored under the supplied {@code key}.
*
* <p>If no value is stored in the current {@link ExtensionContext}
* for the supplied {@code key}, ancestors of the context will be queried
* for a value with the same {@code key} in the {@code Namespace} used
* to create this store. If no value is found for the supplied {@code key},
* a new value will be computed by the {@code defaultCreator} (given
* the {@code key} as input), stored, and returned.
*
* <p>For greater type safety, consider using
* {@link #getOrComputeIfAbsent(Object, Function, Class)} instead.
*
* <p>If the created value is an instance of {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
*
* @param key the key; never {@code null}
* @param defaultCreator the function called with the supplied {@code key}
* to create a new value; never {@code null}
* @param <K> the key type
* @param <V> the value type
* @return the value; potentially {@code null}
* @see #getOrComputeIfAbsent(Class)
* @see #getOrComputeIfAbsent(Object, Function, Class)
* @see CloseableResource
*/
<K, V> Object getOrComputeIfAbsent(K key, Function<K, V> defaultCreator);
Get the value of the specified required type that is stored under the supplied key
. If no value is stored in the current ExtensionContext
for the supplied key
, ancestors of the context will be queried for a value with the same key
in the Namespace
used to create this store. If no value is found for the supplied key
, a new value will be computed by the defaultCreator
(given the key
as input), stored, and returned.
If requiredType
implements CloseableResource
the close()
method will be invoked on the stored object when the store is closed.
Params: - key – the key; never
null
- defaultCreator – the function called with the supplied
key
to create a new value; never null
- requiredType – the required type of the value; never
null
Type parameters: See Also: Returns: the value; potentially null
/**
* Get the value of the specified required type that is stored under the
* supplied {@code key}.
*
* <p>If no value is stored in the current {@link ExtensionContext}
* for the supplied {@code key}, ancestors of the context will be queried
* for a value with the same {@code key} in the {@code Namespace} used
* to create this store. If no value is found for the supplied {@code key},
* a new value will be computed by the {@code defaultCreator} (given
* the {@code key} as input), stored, and returned.
*
* <p>If {@code requiredType} implements {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
*
* @param key the key; never {@code null}
* @param defaultCreator the function called with the supplied {@code key}
* to create a new value; never {@code null}
* @param requiredType the required type of the value; never {@code null}
* @param <K> the key type
* @param <V> the value type
* @return the value; potentially {@code null}
* @see #getOrComputeIfAbsent(Class)
* @see #getOrComputeIfAbsent(Object, Function)
* @see CloseableResource
*/
<K, V> V getOrComputeIfAbsent(K key, Function<K, V> defaultCreator, Class<V> requiredType);
Store a value
for later retrieval under the supplied key
. A stored value
is visible in child
ExtensionContexts
for the store's Namespace
unless they overwrite it.
If the value
is an instance of CloseableResource
the close()
method will be invoked on the stored object when the store is closed.
Params: - key – the key under which the value should be stored; never
null
- value – the value to store; may be
null
See Also:
/**
* Store a {@code value} for later retrieval under the supplied {@code key}.
*
* <p>A stored {@code value} is visible in child {@link ExtensionContext
* ExtensionContexts} for the store's {@code Namespace} unless they
* overwrite it.
*
* <p>If the {@code value} is an instance of {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
*
* @param key the key under which the value should be stored; never
* {@code null}
* @param value the value to store; may be {@code null}
* @see CloseableResource
*/
void put(Object key, Object value);
Remove the value that was previously stored under the supplied key
. The value will only be removed in the current ExtensionContext
, not in ancestors. In addition, the CloseableResource
API will not be honored for values that are manually removed via this method.
For greater type safety, consider using remove(Object, Class<Object>)
instead.
Params: - key – the key; never
null
See Also: Returns: the previous value or null
if no value was present for the specified key
/**
* Remove the value that was previously stored under the supplied {@code key}.
*
* <p>The value will only be removed in the current {@link ExtensionContext},
* not in ancestors. In addition, the {@link CloseableResource} API will not
* be honored for values that are manually removed via this method.
*
* <p>For greater type safety, consider using {@link #remove(Object, Class)}
* instead.
*
* @param key the key; never {@code null}
* @return the previous value or {@code null} if no value was present
* for the specified key
* @see #remove(Object, Class)
*/
Object remove(Object key);
Remove the value of the specified required type that was previously stored under the supplied key
. The value will only be removed in the current ExtensionContext
, not in ancestors. In addition, the CloseableResource
API will not be honored for values that are manually removed via this method.
Params: - key – the key; never
null
- requiredType – the required type of the value; never
null
Type parameters: - <V> – the value type
See Also: Returns: the previous value or null
if no value was present for the specified key
/**
* Remove the value of the specified required type that was previously stored
* under the supplied {@code key}.
*
* <p>The value will only be removed in the current {@link ExtensionContext},
* not in ancestors. In addition, the {@link CloseableResource} API will not
* be honored for values that are manually removed via this method.
*
* @param key the key; never {@code null}
* @param requiredType the required type of the value; never {@code null}
* @param <V> the value type
* @return the previous value or {@code null} if no value was present
* for the specified key
* @see #remove(Object)
*/
<V> V remove(Object key, Class<V> requiredType);
}
A Namespace
is used to provide a scope for data saved by extensions within a Store
. Storing data in custom namespaces allows extensions to avoid accidentally
mixing data between extensions or across different invocations within the
lifecycle of a single extension.
/**
* A {@code Namespace} is used to provide a <em>scope</em> for data saved by
* extensions within a {@link Store}.
*
* <p>Storing data in custom namespaces allows extensions to avoid accidentally
* mixing data between extensions or across different invocations within the
* lifecycle of a single extension.
*/
class Namespace {
The default, global namespace which allows access to stored data from
all extensions.
/**
* The default, global namespace which allows access to stored data from
* all extensions.
*/
public static final Namespace GLOBAL = Namespace.create(new Object());
Create a namespace which restricts access to data to all extensions which use the same sequence of parts
for creating a namespace. The order of the parts
is significant.
Internally the parts
are compared using Object.equals(Object)
.
/**
* Create a namespace which restricts access to data to all extensions
* which use the same sequence of {@code parts} for creating a namespace.
*
* <p>The order of the {@code parts} is significant.
*
* <p>Internally the {@code parts} are compared using {@link Object#equals(Object)}.
*/
public static Namespace create(Object... parts) {
Preconditions.notEmpty(parts, "parts array must not be null or empty");
Preconditions.containsNoNullElements(parts, "individual parts must not be null");
return new Namespace(parts);
}
private final List<?> parts;
private Namespace(Object... parts) {
this.parts = new ArrayList<>(Arrays.asList(parts));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Namespace that = (Namespace) o;
return this.parts.equals(that.parts);
}
@Override
public int hashCode() {
return this.parts.hashCode();
}
}
}