Skip to content

Commit 685132a

Browse files
authored
[RESTEASY-1865] ported proposed code changes to branch (#2625)
1 parent 771f2c6 commit 685132a

File tree

4 files changed

+132
-39
lines changed

4 files changed

+132
-39
lines changed

resteasy-jaxrs/src/main/java/org/jboss/resteasy/core/ResourceMethodRegistry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ protected void register(ResourceFactory rf, String base, ResourceClass resourceC
281281
{
282282
processMethod(rf, base, method);
283283
}
284+
285+
if (rf instanceof SingletonResource) {
286+
providerFactory.registerSingletonResource((SingletonResource) rf);
287+
}
284288
}
285289

286290
/**

resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/server/resourcefactory/SingletonResource.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ public void registered(ResteasyProviderFactory factory)
3636
factory.getInjectorFactory().createPropertyInjector(resourceClass, factory).inject(obj);
3737
}
3838

39-
public Object createResource(HttpRequest request, HttpResponse response, ResteasyProviderFactory factory)
40-
{
39+
public Object createResource(HttpRequest request, HttpResponse response, ResteasyProviderFactory factory) {
4140
return obj;
4241
}
4342

resteasy-jaxrs/src/main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.jboss.resteasy.plugins.delegates.NewCookieHeaderDelegate;
3232
import org.jboss.resteasy.plugins.delegates.UriHeaderDelegate;
3333
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
34+
import org.jboss.resteasy.plugins.server.resourcefactory.SingletonResource;
3435
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
3536
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
3637
import org.jboss.resteasy.specimpl.LinkBuilderImpl;
@@ -108,6 +109,7 @@
108109
import java.util.Set;
109110
import java.util.TreeSet;
110111
import java.util.Map.Entry;
112+
import java.util.concurrent.CompletableFuture;
111113
import java.util.concurrent.ConcurrentHashMap;
112114
import java.util.concurrent.CopyOnWriteArrayList;
113115
import java.util.concurrent.CopyOnWriteArraySet;
@@ -292,6 +294,9 @@ public interface CloseableContext extends AutoCloseable {
292294
private boolean initialized = false;
293295

294296
protected ResourceBuilder resourceBuilder;
297+
// RESTEASY-1865 resource factories for singleton resources
298+
private Map<Class<?>, SingletonResource> singletonResourceFactories;
299+
295300
private StatisticsControllerImpl statisticsController = new StatisticsControllerImpl();
296301

297302
public ResteasyProviderFactory()
@@ -400,6 +405,7 @@ protected void initialize(ResteasyProviderFactory parent)
400405
builtinsRegistered = false;
401406
registerBuiltins = true;
402407

408+
singletonResourceFactories = new HashMap<>();
403409
injectorFactory = parent == null ? new InjectorFactoryImpl() : parent.getInjectorFactory();
404410
registerDefaultInterceptorPrecedences();
405411
addHeaderDelegateIfAbsent(MediaType.class, new MediaTypeHeaderDelegate());
@@ -2859,6 +2865,16 @@ public <T> T injectedInstance(Class<? extends T> clazz)
28592865
return (T) obj;
28602866
}
28612867

2868+
public void registerSingletonResource(SingletonResource resource)
2869+
{
2870+
singletonResourceFactories.put(resource.getScannableClass(), resource);
2871+
}
2872+
2873+
private <T> boolean isSingletonResource(Class<T> resourceClass)
2874+
{
2875+
return singletonResourceFactories.containsKey(resourceClass);
2876+
}
2877+
28622878
/**
28632879
* Property and constructor injection using the InjectorFactory.
28642880
*
@@ -2868,68 +2884,55 @@ public <T> T injectedInstance(Class<? extends T> clazz)
28682884
* @param <T> type
28692885
* @return instance of type T
28702886
*/
2871-
public <T> T injectedInstance(Class<? extends T> clazz, HttpRequest request, HttpResponse response)
2872-
{
2873-
Constructor<?> constructor = PickConstructor.pickSingletonConstructor(clazz);
2887+
public <T> T injectedInstance(Class<? extends T> clazz, HttpRequest request, HttpResponse response) {
28742888
Object obj = null;
2875-
if (constructor == null)
2889+
2890+
if (isSingletonResource(clazz))
28762891
{
2892+
SingletonResource factory = singletonResourceFactories.get(clazz);
2893+
obj = CompletableFuture.completedFuture(factory.createResource(request, response, this)).toCompletableFuture().getNow(null);
2894+
}
2895+
else
2896+
{
2897+
Constructor<?> constructor = PickConstructor.pickSingletonConstructor(clazz);
2898+
2899+
if (constructor == null) {
28772900
// TODO this is solely to pass the TCK. This is WRONG WRONG WRONG! I'm challenging.
28782901
if (false)//if (clazz.isAnonymousClass())
28792902
{
28802903
constructor = clazz.getDeclaredConstructors()[0];
28812904
constructor.setAccessible(true);
2882-
if (!Modifier.isStatic(clazz.getModifiers()))
2883-
{
2905+
if (!Modifier.isStatic(clazz.getModifiers())) {
28842906
Object[] args = {null};
2885-
try
2886-
{
2907+
try {
28872908
obj = constructor.newInstance(args);
2888-
}
2889-
catch (InstantiationException e)
2890-
{
2909+
} catch (InstantiationException e) {
28912910
throw new RuntimeException(e);
2892-
}
2893-
catch (IllegalAccessException e)
2894-
{
2911+
} catch (IllegalAccessException e) {
28952912
throw new RuntimeException(e);
2896-
}
2897-
catch (InvocationTargetException e)
2898-
{
2913+
} catch (InvocationTargetException e) {
28992914
throw new RuntimeException(e);
29002915
}
2901-
}
2902-
else
2903-
{
2904-
try
2905-
{
2916+
} else {
2917+
try {
29062918
obj = constructor.newInstance();
2907-
}
2908-
catch (InstantiationException e)
2909-
{
2919+
} catch (InstantiationException e) {
29102920
throw new RuntimeException(e);
2911-
}
2912-
catch (IllegalAccessException e)
2913-
{
2921+
} catch (IllegalAccessException e) {
29142922
throw new RuntimeException(e);
2915-
}
2916-
catch (InvocationTargetException e)
2917-
{
2923+
} catch (InvocationTargetException e) {
29182924
throw new RuntimeException(e);
29192925
}
29202926
}
2921-
}
2922-
else
2923-
{
2927+
} else {
29242928
throw new IllegalArgumentException(Messages.MESSAGES.unableToFindPublicConstructorForClass(clazz.getName()));
29252929
}
2926-
}
2927-
else
2928-
{
2930+
} else {
29292931
ConstructorInjector constructorInjector = getInjectorFactory().createConstructor(constructor, this);
29302932
obj = constructorInjector.construct(request, response);
29312933

29322934
}
2935+
}
29332936
PropertyInjector propertyInjector = getInjectorFactory().createPropertyInjector(clazz, this);
29342937

29352938
propertyInjector.inject(request, response, obj);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package org.jboss.resteasy.test.core;
2+
3+
import java.io.UnsupportedEncodingException;
4+
import java.net.URISyntaxException;
5+
import java.util.Date;
6+
7+
import javax.ws.rs.GET;
8+
import javax.ws.rs.Path;
9+
import javax.ws.rs.container.ResourceContext;
10+
import javax.ws.rs.core.Context;
11+
12+
import org.jboss.resteasy.core.Dispatcher;
13+
import org.jboss.resteasy.mock.MockDispatcherFactory;
14+
import org.jboss.resteasy.mock.MockHttpRequest;
15+
import org.jboss.resteasy.mock.MockHttpResponse;
16+
import org.junit.Before;
17+
import org.junit.Test;
18+
19+
import static org.junit.Assert.assertEquals;
20+
21+
public class DispatcherTest {
22+
23+
private Dispatcher dispatcher;
24+
25+
26+
@Before
27+
public void before() {
28+
dispatcher = MockDispatcherFactory.createDispatcher();
29+
}
30+
31+
// @see https://issues.jboss.org/browse/RESTEASY-1865
32+
@Test
33+
public void testSingletonResource() throws URISyntaxException, UnsupportedEncodingException {
34+
dispatcher.getRegistry().addSingletonResource(new ParentResource());
35+
dispatcher.getRegistry().addSingletonResource(new ChildResource("I'm singleton child"));
36+
37+
MockHttpRequest request = MockHttpRequest.get("/parent");
38+
MockHttpResponse response = new MockHttpResponse();
39+
40+
dispatcher.invoke(request, response);
41+
42+
assertEquals(200, response.getStatus());
43+
assertEquals("I'm singleton child", response.getContentAsString());
44+
}
45+
46+
47+
48+
49+
@Path("/parent")
50+
public static class ParentResource {
51+
52+
@Context
53+
public ResourceContext resourceCtx;
54+
55+
56+
@GET
57+
public String get() {
58+
ChildResource child = resourceCtx.getResource(ChildResource.class);
59+
return child.get();
60+
}
61+
62+
}
63+
64+
@Path("child")
65+
public static class ChildResource {
66+
67+
private final String name;
68+
69+
70+
@SuppressWarnings("unused") // Not used if RESTEASY-1865 is fixed
71+
public ChildResource() {
72+
this.name = "I'm new child created on " + new Date();
73+
}
74+
75+
public ChildResource(final String name) {
76+
this.name = name;
77+
}
78+
79+
80+
@GET
81+
public String get() {
82+
return name;
83+
}
84+
85+
}
86+
87+
}

0 commit comments

Comments
 (0)