Skip to content

Commit a1c8068

Browse files
jansupolsenivam
authored andcommitted
Order release of RequestScoped beans to prevent NPE
Signed-off-by: jansupol <[email protected]>
1 parent bbaa587 commit a1c8068

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,8 +16,9 @@
1616

1717
package org.glassfish.jersey.inject.hk2;
1818

19-
import java.util.HashMap;
20-
import java.util.HashSet;
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.LinkedHashMap;
2122
import java.util.Map;
2223
import java.util.concurrent.atomic.AtomicInteger;
2324
import java.util.logging.Level;
@@ -63,7 +64,7 @@ public static final class Instance implements org.glassfish.jersey.process.inter
6364
private final AtomicInteger referenceCounter;
6465

6566
private Instance() {
66-
this.store = new HashMap<>();
67+
this.store = new LinkedHashMap<>();
6768
this.referenceCounter = new AtomicInteger(1);
6869
}
6970

@@ -140,7 +141,9 @@ public boolean contains(ForeignDescriptor provider) {
140141
public void release() {
141142
if (referenceCounter.decrementAndGet() < 1) {
142143
try {
143-
new HashSet<>(store.keySet()).forEach(this::remove);
144+
ArrayList<ForeignDescriptor> reverse = new ArrayList<>(store.keySet());
145+
Collections.reverse(reverse);
146+
reverse.forEach(this::remove);
144147
} finally {
145148
logger.debugLog("Released scope instance {0}", this);
146149
}

tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,6 +17,8 @@
1717
package org.glassfish.jersey.tests.e2e.common.process.internal;
1818

1919
import java.lang.reflect.Type;
20+
import java.util.concurrent.atomic.AtomicInteger;
21+
import java.util.function.Consumer;
2022

2123
import org.glassfish.jersey.inject.hk2.Hk2RequestScope;
2224
import org.glassfish.jersey.internal.inject.ForeignDescriptor;
@@ -25,6 +27,7 @@
2527
import org.glassfish.hk2.api.ServiceHandle;
2628
import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
2729

30+
import org.junit.jupiter.api.Assertions;
2831
import org.junit.jupiter.api.Test;
2932
import static org.junit.jupiter.api.Assertions.assertEquals;
3033
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -140,6 +143,34 @@ public void testMultipleGetInstanceCalls() throws Exception {
140143
assertNull(instance.get(inhab));
141144
}
142145

146+
@Test
147+
public void testOrderOfRelease() {
148+
final RequestScope requestScope = new Hk2RequestScope();
149+
final AtomicInteger instanceRelease = new AtomicInteger(0);
150+
final Hk2RequestScope.Instance instance = requestScope.runInScope(() -> {
151+
final Hk2RequestScope.Instance internalInstance = (Hk2RequestScope.Instance) requestScope.current();
152+
for (int index = 1; index != 10; index++) {
153+
final int in = index;
154+
TestProvider testProvider = new TestProvider(String.valueOf(in)) {
155+
@Override
156+
public int hashCode() {
157+
return super.hashCode() + in;
158+
}
159+
};
160+
final ForeignDescriptor fd = ForeignDescriptor.wrap(testProvider, new Consumer<Object>() {
161+
@Override
162+
public void accept(Object o) {
163+
instanceRelease.set(instanceRelease.get() * 10 + in);
164+
}
165+
});
166+
internalInstance.put(fd, String.valueOf(index));
167+
}
168+
return internalInstance;
169+
});
170+
instance.release();
171+
Assertions.assertEquals(987654321, instanceRelease.get());
172+
}
173+
143174
/**
144175
* Test request scope inhabitant.
145176
*/

0 commit comments

Comments
 (0)