quarkus(vertx) how to get request body in a blocking way - jax-rs

What I've tried:
inject CurrentVertxRequest context and then get body from there
#Path("/map_event")
public class MapEventApi {
#Inject
CurrentVertxRequest reqContext;
#POST
#Consumes({ "application/json" })
#Produces({ "application/json" })
Response create(#Valid MapEvent mapEvent, #Context SecurityContext securityContext) throws Exception {
String body = reqContext.getCurrent().getBodyAsString();
...
}
}
but this will give a warning:
2022-01-25 18:22:08,854 WARN [null:-1] (executor-thread-0) BodyHandler in not enabled on this route: RoutingContext.getBodyAsString(...) in always be NULL
another try:
inject standard JaxRS HttpServletRequest context
#Context HttpServletRequest
will get this error:
org.jboss.resteasy.spi.LoggableFailure: RESTEASY003880: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:155)
at com.sun.proxy.$Proxy97.getInputStream(Unknown Source)
I guess it's because quarkus use vertx under the hood so injecting regular jaxrs context won't work since it's not the same thread.

According to #geoand proposiiton following solution worked for me:
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_JSON)
Response create(String body) throws Exception {
...
}
consuming the request as String was the trick → #Consumes(MediaType.TEXT_PLAIN)

Related

javax.ws.rs.ProcessingException: RESTEASY003215: could not find writer for content-type application/json type: com.test.Request

I am using JAX-RS to develop an endpoint, I have the following class:
public class Request implements Serializable {
private String key;
private Content content;
private List<String> user;
}
And this is the endpoint that is configured:
#Path("/api/v1")
public class MyAPI {
#POST
#Path("/alerts")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
String postAlerts(Request request) throws WebApplicationException{
//Implementation
}
}
When I invoke the end point from client, I get following exception:
javax.ws.rs.ProcessingException: RESTEASY003215: could not find writer for content-type application/json type: com.test.Request
I have included all the dependencies mentioned in RESTEasy: Could not find writer for content-type application/json type. Specifically [resteasy-jaxrs, jaxrs-api, resteasy-jaxb-provider, resteasy-jackson2-provider] and I am able to verfiy that they are present in the classpath. Do I need provide some annotations on the 'Request' class which would create a writer for that for content-type application/json?

Jersey ignores ExceptionMapper

I made an ExceptionMapper to catch and log all exceptions, like:
#Provider
public class CatchAllExceptionsMapper implements ExceptionMapper<Throwable> {
private static final Logger LOG = LoggerFactory.getLogger(CatchAllExceptionsMapper.class);
#Override
public Response toResponse(Throwable exception) {
LOG.error("Exception not catched!", exception);
return Response.serverError().build();
}
}
It catches the Exceptions my code throws, but if I send a Request with a JSON value that throws an IllegalStateException at my object's creation, this ExceptionMapper is ignored and I get a 400 Bad Request Response.
Funny thing is this Response is not the traditional Tomcat HTML formatted Response, its just plain text. It say just:
Cannot construct instance of `com.example.vo.AutoValue_Customer$Builder`, problem: First name is null or empty. at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 14, column: 1]
I thought this might be something short-circuiting Jersey, but my #PreMatching ContainerRequestFilter is executed beforehand, so I really have no idea why the 400 Response is not the traditional HTML one from Tomcat.
Why is this happening? What can I do to catch this and return my own Response?
As stated by Paul Samsotha in the comments, JacksonFeature from the jersey-media-json-jackson package define some ExceptionMappers, like JsonMappingException and JsonParseException. The solution is to create our own, register them within the ResourceConfig and register JacksonFeature last, otherwise it won't work.
e.g.
#Provider
#Priority(1) // hack for overriding other implementations.
public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
#Override
public Response toResponse(JsonMappingException exception) {
return Response.status(Status.BAD_REQUEST).build();
}
}
#Provider
#Priority(1) // hack for overriding other implementations.
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
#Override
public Response toResponse(JsonParseException exception) {
return Response.status(Status.BAD_REQUEST).build();
}
}
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(CatchAllExceptionsMapper.class);
register(JsonMappingExceptionMapper.class);
register(JsonParseExceptionMapper.class);
register(JacksonFeature.class);
}
}

Resteasy client : How to set Context Params

I'm using Resteasy client to run test cases for my Service. In application We set context Params in a session check filter,(which implements ContainerRequestFilter). I'm trying to set the same, in Resteasy client, using by adding a ClientRequestFilter implementation, but the property is not recognized, in the service call.
//Resteasy client calling logic
ResteasyClient resteasyClient = new ResteasyClientBuilder().build();
resteasyClient.register(new MyClientRequestFilter());
resteasyClient.target("http://localhost:" + port + "/myPath").request()
.post(Entity.json(authorization_reqParams)).readEntity(String.class));
//filter
public class MyClientRequestFilter implements ClientRequestFilter
{
#Override
public void filter(ClientRequestContext requestContext) throws IOException
{
requestContext.setProperty("CUSTOMER_ATTRIBUTE", "myCustomValue");
}
}
//Rest service method
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response subpartner(Authorization_ReqParams authorizationReqParams, #Context HttpHeaders headers,
#Context HttpServletRequest request, #Context HttpServletResponse response)
{
String myAttribute= request.getAttribute("CUSTOMER_ATTRIBUTE");
//myAttribute is returned as null always
//additional logic
}
I'm able to set&get Header paramets with the same implementation, but Request param is always read as null.
How can I set the request context params ?
In MyClientRequestFilter you add a propery to the request object. What you really want is to send a header instead.
Try this instead:
#Override
public void filter(ClientRequestContext requestContext) {
MultivaluedMap<String, Object> headers = requestContext.getHeaders();
headers.add("CUSTOMER_ATTRIBUTE", "myCustomValue");
}
And read it like this:
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response subpartner(Authorization_ReqParams authorizationReqParams, #Context HttpHeaders headers,
#Context HttpServletRequest request, #Context HttpServletResponse response)
{
String myAttribute= headers.getRequestHeader("CUSTOMER_ATTRIBUTE");
//additional logic
}

jaxrs queryparam not loaded for interceptor

I have a REST service of the form:
#GET
#NeedsInterception
public void getSomething(#QueryParam("xxx") #MyAnnotation String thing) {
//Stuff
}
I then have an interceptor for #NeedsInterception.
In it, I perform some logic on the element annotated with #MyAnnotation.
However, when the interceptor is called, the MethodInvocation object has not yet been resolved with the value of the QueryParam, instead it is always "";
Is there a way for me to make the interception happen after the QueryParam is resolved?
Don't know which kind of interceptor you are using but a jax-rs ReaderInterceptor is intended to wrap calls to MessageBodyReader.readFrom. As you don't send a request body with a #GET request this kind of interceptor won't be used.
A ContainerRequestFilter should help:
#Provider
public class SomeFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MultivaluedMap<String,String> queryParameters = requestContext.getUriInfo().getQueryParameters();
}
}

JAX-RS enabling CORS (Access-Control-Allow-Origin) on Glassfish 4

I am working in JAVA EE7, JAX-RS 2.0 Glassfish 4 is my SERVER.
I Want to work on CORS to enable Ajax Requests comming out of my domain.
I know that I need to make my server enabling it. And I did it in PHP. like the following code:
<?php header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization");
but when I tried to do the same thing I always get an error message like that
"this is a screenshot".
So I've tried to modify the sever http response with many ways...
And this is my code , server side , I used a filer/provider:
#Provider
#CORSBinding
public class Filter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext request) throws IOException {
request.getHeaders().add("Access-Control-Allow-Origin", "*");
request.getHeaders().add("Access-Control-Allow-Headers", "Authorization");
if (request.getMethod().equals("OPTIONS")) {
System.out.println("OPTIONS is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("GET")) {
System.out.println("GET is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("POST")) {
System.out.println("POST is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("DELETE")) {
System.out.println("DELETE is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("PUT")) {
System.out.println("PUT is requested!!!!!!!!!!!!!");
}
}
}
But it seems like all blocked by a "firewall security" provided by Glassfish4 server.
here is my simple code javascript:
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8080/CV/api/v2/posts");
xhr.setRequestHeader('Authorization', 'a');
xhr.send();
</script>
I even added an other filter using the #Prematching annotation to update the request from OPTIONS TO POST ... but I always lose my headers that I have sent within it (I mean within POST request).
#Provider
#PreMatching
public class HttpMethodOverrideEnabler implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.setMethod("POST");
containerRequestContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerRequestContext.getHeaders().add("Access-Control-Allow-Headers","Authorization");
containerRequestContext.getHeaders().add("Access-Control-Allow-Headers","Authorization");
String override = containerRequestContext.getHeaders().getFirst( "X-HTTP-Method-Override");
if (override != null) {
containerRequestContext.setMethod(override);
}
}
I knew that Glassfish3 had not the support for CORS and ("https://java.net/jira/browse/GLASSFISH-16049) they said that they will fix it with JEE7.
This is the whole story...
so how can I do the CORS with this JEE7 using Glassfish server and JAX-RS2.
Thanks in advance.
Use ContainerResponseFilter not ContainerRequestFilter as you want to add those headers into response and not to the request. For example:
#Provider
#Priority(Priorities.HEADER_DECORATOR)
public class AccessControlResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
final MultivaluedMap<String,Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
headers.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type");
headers.add("Access-Control-Expose-Headers", "Location, Content-Disposition");
headers.add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, HEAD, OPTIONS");
}
}
You have to use the 2 *filters* the First because Chrome and other Browsers modify the headers for security purpose, and the second is to add the headers to response. So use ContainerResponseFilter and ContainerRequestFilter. it works fine with me Good luck!