Jersey client proxy not resolving calls to URI with multiple path params - java

I have the following javax rs annotated interface:
#Path("/")
public interface MyRestEndpoint {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("myapp/resources/resourceId/{resourceId}/memberId/{memberId}")
MyResource findMyResource(#PathParam("resourceId") int resourceId,
#PathParam("memberId") long memberId);
Which I am calling via a jersey proxy client created as such:
MyRestEndpoint myRestEndpointForTests = WebResourceFactory.newResource(MyRestEndpoint.class, lobbyClient().target(myHost));
...
myRestEndpointForTests.findMyResource(resourceId, memberId);
But when I do so, I get the following exception:
java.lang.IllegalStateException: Unresolved variables; only 0 value(s) given for 2 unique variable(s)
at org.glassfish.jersey.client.JerseyWebTarget.getUri(JerseyWebTarget.java:134)
at org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:214)
at org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:59)
at org.glassfish.jersey.client.proxy.WebResourceFactory.invoke(WebResourceFactory.java:312)
at com.sun.proxy.$Proxy89.findCurrentTableOfPlayer(Unknown Source)
Having debugged somewhat through the Jersey codebase, it seems that the WebResourceFactory is trying to create a WebTarget by looping over the annotations on the MyRestEndpoint class. It picks up both annotations, and both provided values but seems to overwrite any previously resolved path params as it loops over them (so its left with only the memberId path param being resolved). Can anyone explain why? Is this a bug or expected behaviour? How can I support multiple path params?
I know this is specific to having more than one path parameter configured via annotation. As I have other methods in the annotated interface that have only one path parameter and work perfectly when called in the same way.
I'm using Jersey v2.16 components and Javax rs v2.0.1 components

Looks like WebResourceFactory is not actively developed also it's source code was quite hard to understand for me.
So we created another implementation of proxing rest interfaces.
Feel free to try https://github.com/adaptris/jaxrs-client-proxy implementation. It's under development currently so for sure have some bugs.

Related

multiple parameters with no annotation error on Javax WS and retrofit when I use "suspend" , how to handle?

I am creating a very basic controller using Kotlin with javax.ws and retrofit libraries.
I created a controller like this...
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
suspend fun sayHello(request: StudentRequest): StudentResponse {
that basically calls another service.
But when I run the app I get this error:
[FATAL] Method public final java.lang.Object MyResource.sayHello(StudentRequest,kotlin.coroutines.Continuation) on resource class MyResource contains multiple parameters with no annotation. Unable to resolve the injection source.;
handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#a0bf272]},
definitionMethod=public final java.lang.Object my.org.package.MyResource(sayHello,k**otlin.coroutines.Continuation**),
the weird part is that are couple of similar posts Jersey #PathParam : contains multiple parameters with no annotation
How can I pass multiple parameter to restful webservice using http post
https://github.com/dropwizard/dropwizard/issues/1115
but are not the same because my problem is with my ONLY parameter
There is no missing tag to my body request and I basically dont know what to look for at this point, any idea what could be wrong with this?
After debugging I noticed that there are two parameters, mine and one injected by Kotlin, when removing the "suspend" everything works fine, but then I am not able to make my async call.
To use coroutines from blocking code you need to use coroutine builder (e.g. launch {} or runBlocking {}).
Unfortunately in this case you can't just mark your glassfish controller as a suspendable function because framework don't know how to deal with continuations.

Resolving Template Variable in Resource Interface for Jersey Proxy Client

I have an issue resolving a class-level #Path annotation on a interface as such. I'm passing this interface to a WebResourceFactory in Jersey proxy client but it's immediately failing with an IllegalStateException.
The interface definition:
#Path("{entity}")
public interface EntityResource {
#GET
#Produces("*/xml")
Entity get(#PathParam("view") EntityType view);
}
The exception I get:
Exception in thread "main" java.lang.IllegalStateException: The template variable 'entity' has no value
at org.glassfish.jersey.client.JerseyWebTarget.getUri(JerseyWebTarget.java:135)
at org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:215)
at org.glassfish.jersey.client.JerseyWebTarget.request(JerseyWebTarget.java:60)
at org.glassfish.jersey.client.proxy.WebResourceFactory.invoke(WebResourceFactory.java:322)
Any suggestions on how to resolve the "entity" template variable?
After doing some investigation in the jersey-proxy-client source code, I found that all template variables are resolved with annotations on the method declaration. There was an issue in how Apache CXF generated my interfaces. I have a mismatch between the #PathParam and the #Path. #Path uses "entity" and my #PathParam uses "view". They both need to be the same in order for the template variable to resolve correctly.
I faced similar problem and I was able to resolve it without matching #Path and #PathParam values. I used #RequestTemplate which actually does transformation from entity into view:
#APIGatewayIntegration(
requestTemplates =
#RequestTemplate(
mimeType = MediaType.APPLICATION_JSON,
template = "{\"entity\": \"$input.params('view')\"}"),
type = "aws",
contentHandling = "CONVERT_TO_TEXT",
httpMethod = HTTP_POST_METHOD,
passthroughBehavior = "WHEN_NO_TEMPLATES"
)
I use my interface in AWS API GW. Hope this will be useful.

AspectJ with Spring : intercepted methods lose their parameters annotations

I recently added AOP with aspectJ and spring-aop to my existent spring project. The goal was to actually intercept controller calls to modify the response they send back, in order to bind some values to this response I didn't want to add manually to each and everyone of my controllers, for example the expiration date of the actual token used by the end-user (which I wasn't even able to showcase within my controller in any case). I actually managed to get it working until I started my unit tests :
In my unit tests I call directly my controller methods using Reflection feature from java, then replicate usual process (calling the filter chain, pre handler and post handlers, and the controller method itself which is first manually validated using spring validator when annotation #Valid is present on one of my parameters. All this process works fine and gets executed properly). The problem is that now that the controller method is intercepted by spring-aop, it's mentionned as coming from the proxy controller created, and all of my parameters annotations disapear. Here is a controller example :
#Override
public ResponseEntity<Object> editPassword(#Valid #RequestBody PasswordEditForm passwordEditForm, HttpServletRequest request) {
return factorizedUserBaseController.editPassword(passwordEditForm, request, User.class);
}
the parameter PasswordEditForm has the annotation #Valid so in my test cases it was first validated before any other step, but now as I double checked it, the #Valid annotation is not present on the proxy method, and therefore the parameter doesn't get validated, any clue for how to fix this and make my parameters annotation still understandable from my test point of view?
Note : when running the spring through mvn spring-boot:run, parameters with #Valid annotation gets correctly validated and then goes to my error handler method properly.
Problem Solved : from several other stackoverflow posts I understand that CGLIB (aop proxy lib used by Spring) doesn't support annotations. ( see Retain annotations on CGLIB proxies?). But my problem wasn't here, I was literally sure I was finding the method using the controller class itself (the one I coded) but what I was wrong about is that I was giving the controller instance as a parameter to some other parts of my code which in turn would use this controller class to find the method which of course wasn't working because thanks to Spring proxies, it wasn't anymore my controller itself but a proxy class extending my own controller class. Instead, I just had to replace :
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass();
with
Class<?> controllerClass = controllerInstanciationContainer
.getController()
.getClass()
.getSuperclass();

GenericType unmarshalling fails in spring restful

Given below is the scenario in which I am facing difficulty, I am using Restful based webservice in spring MVC where I am ineracting with JSON.
I have a class :
RegexObject and another class RegexObjectDME extends RegexObject.
RegexObject is in one common project, which is being used as it is in webservice consumer and RegexObjectDME in webservice provider.
Now, There is another bean in the same common project, Say HDTaskInfoBean ,
There are two child beans extending HDTaskInfoBean as
HDTaskInfoBeanClient extends HDTaskInfoBean<RegexObject>
and
HDTaskInfoBeanAgent extends HDTaskInfoBean<RegexObjectDME> .
The RegexObjectDME and RegexObject have same properties except a few methods.
HDTaskInfoBeanClient and HDTaskInfoBeanAgent too have same properties and there is generic setter getters for regexObject and regexObjectDME. The T type property name is regexArray.
HDTaskInfoBeanClient is used while making request and HDTaskInfoBeanAgent is used on webservice side.
I am getting the following exception:
Syntactical Error.
Another Scenario I used string as requestbody and tried to unmarshall it into Java Object using Gson() , It gave error:
Request processing failed; nested exception is java.lang.UnsupportedOperationException: Expecting parameterized type, got class com.*.
Are you missing the use of TypeToken idiom?
Please help, I want to use **HDTaskInfoBeanClient ** in Request and HDTaskInfoBeanAgent on webservice provider side. If there is any alternative to it, Kindly suggest.
Thanks in advance :)
I am not sure that why did this weird behavior was shown by default message converter which Comes with Spring Framework.
I found that one of the very good message converter from JSON to Object and back is GSON(A utility by Google) .
One reliable approach to handle such a problem is write your own Custom Message Converter by overriding a class and Using GSON in that. Here is the link for such a solution. I hope it helps you as a solution and would be more reliable.
Regards,
Rahul

Using MessageBodyReader for multiple parameters in RESTful services

The following method does not allow my servlet container to start:
#PUT
public String upload(final Customer customer, final Control control) {
// ...
}
I get, not surprisingly:
SEVERE: Missing dependency for method ... at index 0
SEVERE: Missing dependency for method ... index 1
SEVERE: Method, ..., is not recognized as valid resource method.
I have implemented MessageBodyReaders for each type. Removing any of the parameters enables the servlet container to start gracefully, so I suspect there must be a restriction on the number of parameters that will be resolved via Entity-Providers.
The problem is that I NEED these two parameters, since I am providing both SOAP and REST support, and of course, I am not in the liberty of changing method signatures, and I also do not want to create one specific Jersey method and one specific JAX-WS method as entry points.
I'm using Jersey 1.7.
JAX-RS allows only one entity parameter. The reson is very simple: each request may have at most one body (multiparts are not supported by spec)
So you must create two methods.
Btw, I don't think it's a good practice to mix JAXRS and JAXWS in the same class.

Categories