Skip to content

bmuskalla/scoped-system-properties

Repository files navigation

Scoped System Properties

Build

tldr;

Easy to use, lock-free, thread-safe scoped system properties to isolate changes to global state.

Motivation

If you need to change system properties for specific calls to 3rd party APIs, you could just use a try/finally construct. The downside is that you need to ensure that no other code in parallel tries to read/write the same system properties. Other folks use a global lock to around the try/finally to avoid any other thread in the system to see this particular state.

While generally, your code should abstract away access to global state like system properties, 3rd party code you use may not do that. Too many libraries rely on specific system properties for configuration or feature toggles.

This library helps to deal with those 3rd party dependencies that require the usage of system properties by isolating access and mutation to said system properties.

Library

Gradle

Groovy

implementation 'io.github.bmuskalla:scoped-system-properties:1.1.0'

Kotlin

implementation("io.github.bmuskalla:scoped-system-properties:1.1.0")

Maven

<dependency>
    <groupId>io.github.bmuskalla</groupId>
    <artifactId>scoped-system-properties</artifactId>
    <version>1.1.0</version>
</dependency>

Example (as library)

System.setProperty("someKey", "global value");
try (PropertyEnvironment env = ScopedSystemProperties.newPropertyEnvironment()) {
    env.setProperty("someKey", "scopedValue");
    // or using the usual Java APIs
    // System.setProperty("someKey", "scopedValue");

    System.getProperty("someKey"); // = "scopedValue"

    // another thread calling System.getProperty("someKey") will see `global value`
}
System.getProperty("someKey") // = "global value"

JUnit 5 Extension

Gradle

Groovy

implementation 'io.github.bmuskalla:scoped-system-properties-junit:1.1.0'

Kotlin

implementation("io.github.bmuskalla:scoped-system-properties-junit:1.1.0")

Maven

<dependency>
    <groupId>io.github.bmuskalla</groupId>
    <artifactId>scoped-system-properties-junit</artifactId>
    <version>1.1.0</version>
</dependency>

Example (in JUnit Jupiter)

@BeforeEach
void setUp() {
    assertEquals("baseline", System.getProperty("key"));
    System.setProperty("key", "before");
}

@Test
@IsolatedSystemProperties
void setsValueInTest() throws Exception {
    assertEquals("before", System.getProperty("key"));
    System.setProperty("key", "other");
}

@AfterAll
static void tearDown() {
    assertEquals("baseline", System.getProperty("key"));		
}

@IsolatedSystemProperties can be used on individual test methods or on the whole test class. In both cases, the individual test (and the respective lifecycle methods like @BeforeEach) will be isolated against the rest of the environment.

Alternative approach using JUnit

Proper isolation can be achieved by leveraging a global lock using JUnits @ResourceLock (see Synchronization when running Parallel Tests). While this has the same effect of avoiding race conditions on the system properties, such tests cannot be run in parallel if they require mutating access to system properties.

Changelog

1.1.0

  • Avoid global changes to affect the isolated environment
  • Support all Properties API
  • Simplified delegation

1.0.0 Reworked API

  • Favor PropertyEnvironment as concept

0.5.0 Initial release

  • Support as standalone library
  • Support as JUnit 5 extension

About

Easy to use, lock-free, thread-safe scoped system properties to avoid changing global state.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published