Prevent 'Recursive update' exceptions with Restarter

Update `Restarter` to prevent 'Recursive update' `IllegalStateException`
from being thrown. Calls to `objectFactory.getObject()` now happen
outside of `computeIfAbsent`.

Fixes gh-41571
This commit is contained in:
Phillip Webb 2024-09-03 12:07:33 -07:00
parent 978ee338a8
commit aeafa20727
2 changed files with 22 additions and 4 deletions

View File

@ -440,7 +440,12 @@ public class Restarter {
}
public Object getOrAddAttribute(String name, final ObjectFactory<?> objectFactory) {
return this.attributes.computeIfAbsent(name, (ignore) -> objectFactory.getObject());
Object value = this.attributes.get(name);
if (value == null) {
value = objectFactory.getObject();
this.attributes.put(name, value);
}
return value;
}
public Object removeAttribute(String name) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -145,15 +145,28 @@ class RestarterTests {
}
@Test
@SuppressWarnings("rawtypes")
void getOrAddAttributeWithExistingAttribute() {
Restarter.getInstance().getOrAddAttribute("x", () -> "abc");
ObjectFactory objectFactory = mock(ObjectFactory.class);
ObjectFactory<?> objectFactory = mock(ObjectFactory.class);
Object attribute = Restarter.getInstance().getOrAddAttribute("x", objectFactory);
assertThat(attribute).isEqualTo("abc");
then(objectFactory).shouldHaveNoInteractions();
}
@Test
void getOrAddAttributeWithRecursion() {
Restarter restarter = Restarter.getInstance();
Object added = restarter.getOrAddAttribute("postgresContainer", () -> {
restarter.getOrAddAttribute("rabbitContainer", () -> "def");
return "abc";
});
ObjectFactory<?> objectFactory = mock(ObjectFactory.class);
assertThat(added).isEqualTo("abc");
assertThat(restarter.getOrAddAttribute("postgresContainer", objectFactory)).isEqualTo("abc");
assertThat(restarter.getOrAddAttribute("rabbitContainer", objectFactory)).isEqualTo("def");
then(objectFactory).shouldHaveNoInteractions();
}
@Test
void getThreadFactory() throws Exception {
final ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();