3131import org .jboss .resteasy .plugins .delegates .NewCookieHeaderDelegate ;
3232import org .jboss .resteasy .plugins .delegates .UriHeaderDelegate ;
3333import org .jboss .resteasy .plugins .providers .RegisterBuiltin ;
34+ import org .jboss .resteasy .plugins .server .resourcefactory .SingletonResource ;
3435import org .jboss .resteasy .resteasy_jaxrs .i18n .LogMessages ;
3536import org .jboss .resteasy .resteasy_jaxrs .i18n .Messages ;
3637import org .jboss .resteasy .specimpl .LinkBuilderImpl ;
108109import java .util .Set ;
109110import java .util .TreeSet ;
110111import java .util .Map .Entry ;
112+ import java .util .concurrent .CompletableFuture ;
111113import java .util .concurrent .ConcurrentHashMap ;
112114import java .util .concurrent .CopyOnWriteArrayList ;
113115import 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 );
0 commit comments