Skip to content

Commit

Permalink
[RESTEASY-1905] Async injection (#1504)
Browse files Browse the repository at this point in the history
* Turned injection into CompletionStage-using API

* Expand CompletionStages if required

* Support pluggable context injectors

* Implement missing methods in Type subtypes

* PortProviderUtil defaults to localhost

* Alternate test runner to run test in IDE

Just use it in place of Arquillian runner, and you can debug it :)

* Async injection test

* Turn the request async if injected value is not resolved

Also provide annotations to the injector

* Test async injection from other thread

* Do not proxy for async injection

* TEst async injection for interfaces

* Forgot to include annotation in test

* Fixed bug with PatchMethodFilter due to my changes

* Test async injection errors

* Fix injectedInstance

* fix parameterizedtype impl hash/equals to be the same as the jdk

* Only do async injection if supported (only supported for resource creation for method invocation)

* Test behaviour of post-invoke async resource injection

* First pass at supporting pluggable rx types for async injection

* Test async injection for rx Single

* Second pass at doing async injection for rx

* Fix invalid assumptions about CompletionException wrapping

* Run async injection test with arquillian runner

* Something went wrong in rebasing

* Make sure we support async injection of unboxed types

* Test primitive injection
  • Loading branch information
FroMage authored and asoldano committed May 30, 2018
1 parent 0d8d71c commit bd2bc71
Show file tree
Hide file tree
Showing 87 changed files with 2,389 additions and 602 deletions.
Expand Up @@ -60,7 +60,7 @@ public void filter(ContainerRequestContext requestContext) throws IOException
Object object;
try
{
object = methodInvoker.invokeDryRun(request, response);
object = methodInvoker.invokeDryRun(request, response).toCompletableFuture().getNow(null);
ByteArrayOutputStream tmpOutputStream = new ByteArrayOutputStream();
MessageBodyWriter msgBodyWriter = ResteasyProviderFactory.getInstance().getMessageBodyWriter(
object.getClass(), object.getClass(), methodInvoker.getMethodAnnotations(),
Expand Down
Expand Up @@ -17,6 +17,8 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/**
* This ConstructorInjector implementation uses CDI's BeanManager to obtain
Expand All @@ -36,7 +38,8 @@ public CdiConstructorInjector(Type type, BeanManager manager)
this.manager = manager;
}

public Object construct()
@Override
public CompletionStage<Object> construct(boolean unwrapAsync)
{
Set<Bean<?>> beans = manager.getBeans(type);

Expand Down Expand Up @@ -65,21 +68,24 @@ public Object construct()

Bean<?> bean = manager.resolve(beans);
CreationalContext<?> context = manager.createCreationalContext(bean);
return manager.getReference(bean, type, context);
return CompletableFuture.completedFuture(manager.getReference(bean, type, context));
}

public Object construct(HttpRequest request, HttpResponse response) throws Failure, WebApplicationException, ApplicationException
@Override
public CompletionStage<Object> construct(HttpRequest request, HttpResponse response, boolean unwrapAsync) throws Failure, WebApplicationException, ApplicationException
{
return construct();
return construct(unwrapAsync);
}

public Object[] injectableArguments()
@Override
public CompletionStage<Object[]> injectableArguments(boolean unwrapAsync)
{
return new Object[0];
return CompletableFuture.completedFuture(new Object[0]);
}

public Object[] injectableArguments(HttpRequest request, HttpResponse response) throws Failure
@Override
public CompletionStage<Object[]> injectableArguments(HttpRequest request, HttpResponse response, boolean unwrapAsync) throws Failure
{
return injectableArguments();
return injectableArguments(unwrapAsync);
}
}
Expand Up @@ -31,6 +31,8 @@
import javax.ws.rs.WebApplicationException;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/**
* JAX-RS property injection is performed twice on CDI Beans. Firstly by the JaxrsInjectionTarget
Expand Down Expand Up @@ -62,21 +64,23 @@ public CdiPropertyInjector(PropertyInjector delegate, Class<?> clazz, Map<Class<
}

@Override
public void inject(Object target)
public CompletionStage<Void> inject(Object target, boolean unwrapAsync)
{
if (injectorEnabled)
{
delegate.inject(target);
return delegate.inject(target, unwrapAsync);
}
return CompletableFuture.completedFuture(null);
}

@Override
public void inject(HttpRequest request, HttpResponse response, Object target) throws Failure, WebApplicationException, ApplicationException
public CompletionStage<Void> inject(HttpRequest request, HttpResponse response, Object target, boolean unwrapAsync) throws Failure, WebApplicationException, ApplicationException
{
if (injectorEnabled)
{
delegate.inject(request, response, target);
return delegate.inject(request, response, target, unwrapAsync);
}
return CompletableFuture.completedFuture(null);
}

@Override
Expand Down
Expand Up @@ -55,11 +55,11 @@ public void inject(T instance, CreationalContext<T> ctx)

if ((request != null) && (response != null))
{
propertyInjector.inject(request, response, instance);
propertyInjector.inject(request, response, instance, false);
}
else
{
propertyInjector.inject(instance);
propertyInjector.inject(instance, false);
}

if (request != null)
Expand Down
@@ -1,6 +1,9 @@
package org.jboss.resteasy.plugins.guice;

import com.google.inject.Provider;

import java.util.concurrent.CompletionStage;

import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.PropertyInjector;
Expand Down Expand Up @@ -30,11 +33,12 @@ public void registered(ResteasyProviderFactory factory)
propertyInjector = factory.getInjectorFactory().createPropertyInjector(scannableClass, factory);
}

public Object createResource(final HttpRequest request, final HttpResponse response, final ResteasyProviderFactory factory)
@Override
public CompletionStage<Object> createResource(final HttpRequest request, final HttpResponse response, final ResteasyProviderFactory factory)
{
final Object resource = provider.get();
propertyInjector.inject(request, response, resource);
return resource;
return propertyInjector.inject(request, response, resource, true)
.thenApply(v -> resource);
}

public void requestFinished(final HttpRequest request, final HttpResponse response, final Object resource)
Expand Down
Expand Up @@ -7,6 +7,8 @@
import javax.ws.rs.core.MultivaluedMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -42,17 +44,21 @@ protected AbstractCollectionFormInjector(Class collectionType, Class genericType
* {@inheritDoc} Creates a collection instance and fills it with content by using the super implementation.
*/
@Override
public Object inject(HttpRequest request, HttpResponse response)
public CompletionStage<Object> inject(HttpRequest request, HttpResponse response, boolean unwrapAsync)
{
T result = createInstance(collectionType);
CompletionStage<Void> ret = CompletableFuture.completedFuture(null);
for (String collectionPrefix : findMatchingPrefixesWithNoneEmptyValues(request.getDecodedFormParameters()))
{
Matcher matcher = pattern.matcher(collectionPrefix);
matcher.matches();
String key = matcher.group(1);
addTo(result, key, super.doInject(collectionPrefix, request, response));
ret = ret.thenCompose(v -> super.doInject(collectionPrefix, request, response, unwrapAsync)
.thenAccept(value -> {
addTo(result, key, value);
}));
}
return result;
return ret.thenApply(v -> result);
}

/**
Expand Down
Expand Up @@ -8,6 +8,8 @@
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -24,13 +26,13 @@ public AsynchronousResponseInjector()
}

@Override
public Object inject()
public CompletionStage<Object> inject(boolean unwrapAsync)
{
throw new IllegalStateException(Messages.MESSAGES.cannotInjectAsynchronousResponse());
}

@Override
public Object inject(HttpRequest request, HttpResponse response)
public CompletionStage<Object> inject(HttpRequest request, HttpResponse response, boolean unwrapAsync)
{
ResteasyAsynchronousResponse asynchronousResponse = null;
if (timeout == -1)
Expand All @@ -44,6 +46,6 @@ public Object inject(HttpRequest request, HttpResponse response)
ResourceMethodInvoker invoker = (ResourceMethodInvoker)request.getAttribute(ResourceMethodInvoker.class.getName());
invoker.initializeAsync(asynchronousResponse);

return asynchronousResponse;
return CompletableFuture.completedFuture(asynchronousResponse);
}
}

0 comments on commit bd2bc71

Please sign in to comment.