I'm migrating old Quarkus project from RestEasy to ResteasyReactive and I have some difficulties migrating ResteasyContext.pushContext
since there is no real 1:1 alternative in rest easy.
I'm using the ResteasyContext.pushContext
in my ContainerRequestFilter
to push some custom object to Context and later retrieve it using @Context.
Something like in this minimal example i provided.
Filter:
package org.acme.filter;
import org.acme.pojo.CustomHttpRequest;
import org.jboss.resteasy.core.ResteasyContext;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
import java.time.LocalDateTime;
import java.util.Random;
@Provider
@ApplicationScoped
public class HttpRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) {
CustomHttpRequest request = CustomHttpRequest.builder()
.headers(requestContext.getHeaders())
.dateTime(LocalDateTime.now())
.text("Some random text for example " + new Random().nextInt(100))
.build();
ResteasyContext.pushContext(CustomHttpRequest.class, request);
}
}
Custom object I want to push to context:
package org.acme.pojo;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import javax.ws.rs.core.MultivaluedMap;
import java.time.LocalDateTime;
@Getter
@Builder
@ToString
public class CustomHttpRequest {
private String text;
private LocalDateTime dateTime;
private MultivaluedMap<String, String> headers;
private boolean secured;
}
And the later read it from context in my rest endpoint:
package org.acme;
import org.acme.pojo.CustomHttpRequest;
import org.acme.pojo.ResponseData;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@GET
@Path("{pathText}")
@Produces(MediaType.APPLICATION_JSON)
public ResponseData testContext(@Context CustomHttpRequest httpRequest,
@PathParam("pathText") String queryText) {
return ResponseData.builder()
.queryText(queryText)
.httpRequestText(httpRequest.getText())
.secured(httpRequest.isSecured())
.build();
}
}
Here is the full example on GitHub: https://github.com/pkristja/resteasy_context/tree/main
I have found some alternatives that work with RestEasyReactive like using ContainerRequestContext
and setting the data using setProperty.
Build file changes:
Changed from implementation("io.quarkus:quarkus-resteasy-jackson")
to implementation("io.quarkus:quarkus-resteasy-reactive-jackson")
Filter for setting oblect to context:
package org.acme.filter;
import org.acme.pojo.CustomHttpRequest;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import java.time.LocalDateTime;
import java.util.Random;
@Provider
@ApplicationScoped
public class HttpRequestFilter implements ContainerRequestFilter {
@Context
ContainerRequestContext crContext;
@Override
public void filter(ContainerRequestContext requestContext) {
CustomHttpRequest request = CustomHttpRequest.builder()
.headers(requestContext.getHeaders())
.dateTime(LocalDateTime.now())
.text("Some random text for example " + new Random().nextInt(100))
.build();
crContext.setProperty("customHttpRequest", request);
}
}
Retrieving object from context:
package org.acme;
import org.acme.pojo.CustomHttpRequest;
import org.acme.pojo.ResponseData;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@GET
@Path("{pathText}")
@Produces(MediaType.APPLICATION_JSON)
public ResponseData testContext(@Context ContainerRequestContext crContext,
@PathParam("pathText") String queryText) {
CustomHttpRequest httpRequest = (CustomHttpRequest) crContext.getProperty("customHttpRequest");
return ResponseData.builder()
.queryText(queryText)
.httpRequestText(httpRequest.getText())
.secured(httpRequest.isSecured())
.build();
}
}
Is there any way to get same functionality in RestEasyReactive like you had in RestEasy using ResteasyContext.pushContext
because it's really verbose and inefficient to retrieve each object from context and cast it because in my real example I have multiple custom objects pushed to context with ResteasyContext.pushContext
.
Thank you!
When using RESTEasy Reactive, there is a far easier way of doing things like this: just use a CDI request scoped bean.
Something like the following should be just fine:
@Singleton
public class CustomHttpRequestProducer {
@RequestScoped
@Unremovable
public CustomHttpRequest produce(HttpHeaders headers) {
return new CustomHttpRequest(headers.getRequestHeaders(), LocalDateTime.now(), "dummy");
}
}
Then you would use it in your JAX-RS Resource as easily as:
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello(@Context CustomHttpRequest customHttpRequest) {
return customHttpRequest.getText();
}
Note that @Unremovable
is only needed if you use CustomHttpRequest
as method parameter.
If you however inject it as a field, @Unremovable
is unnecessary.
UPDATE
After https://github.com/quarkusio/quarkus/pull/33793 becomes part of Quarkus (likely in 3.2) then @Unremovable
will no longer be necessary even for the method parameter