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.
Related
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.
We were using Resteasy 3.0.9 for our JAX-RS webservices, and recently switched to 3.0.19, where we started to see a lot of RESTEASY002142: Multiple resource methods match request warnings.
For example, we have methods like:
#Path("/{id}")
public String getSome(UUID id)
#Path("/{id}")
public String getSome(int id)
I'm not sure how it worked in 3.0.9, probably, we just were very lucky as Resteasy seems to select first method from all candidates (and 3.0.19 sorts candidate methods).
One solution is to explicitly specify regex: #Path("/{id : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
But is there a way to somehow tell Resteasy to look into method parameters and construct appropriate regex automatically?
As far as I know, RESTEasy won't take the method parameter type into consideration when matching a request. According the JSR-339 (that RESTEasy implements), this is how the request matching process works:
A request is matched to the corresponding resource method or sub-resource method by comparing the normalized
request URI, the media type of any request entity, and the requested response
entity format to the metadata annotations on the resource classes and their methods. If no matching resource
method or sub-resource method can be found then an appropriate error response is returned. [...]
The JAX-RS implementations must match the requested URI with the #Path annotation values. In the #Path annotation value you can define variables, that are denoted by braces ({ and }).
As part of the request matching, the JAX-RS implementation will replace each URI template variable with the specified regular expression or ([ˆ/]+?) if no regular expression is specified.
To address the situation you mentioned in your question, you should specify a regex to match UUIDs on one resource method:
#Path("{id : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
And you also may consider a regex to match integers on the other resource method:
#Path("{id : \\d+}")
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.
1)
I'm dealing with similar situation like at How can I pass complex objects as arguments to a RESTful service? , but actually the injection of my custom XML objects if injected all right, IF i do not annotate method parameter with #Form.
This is wrapper request object to injection:
#XmlRootElement(name = "request")
#XmlAccessorType(XmlAccessType.NONE)
#XmlType
#Consumes({"application/xml", "application/json"})
public class TestRequest {
#PathParam(value = "value")
private String value; // this is injected only when #Form param is added to the method parameter definition
#XmlElement(type = Test.class)
private Test test; // this is XML object I want to inject from the REST request
#XmlElement
private String text; // or inject other XML element like this
}
So this would inject me REST parameters (e.g. {value} - #PathParam("value") annotated in TestRequest).
BUT this doesn't unmarshall the XML object Test in wrapper object TestRequested.
#POST
#Path("tests/{value}")
#Consumes("application/xml")
#Produces("application/xml")
public void addTest(**#Form** TestRequest req);
And following definition would inject only the XML object Test but doesn't inject the REST annotations (e.g. {value} from URI):
public void addTest(TestRequest req); // without #Form annotation now
2) I also tried another approach by catching request to custom MessageBodyReader implementation but have been lost in the details where to find code, method or class of JAX-RS or RESTEasy that actually does this parsing/injecting of REST annotations(#PathParam, #QueryParam,...).
I also noticed that when there is #Form annotation in method definition, then custom MessageBodyReader isn't even catched (propably built-in one for REST parameters catches that request and custom reader is then ignored).
I could in this custom message body reader solution somehow call that built-in injection provider but i didn't find suitable documentation and it seems I'm doing something wrong and all can be done more simplier some other way.
To summarise the goal: inject both REST parameters (#PathParam, #QueryParam etc.) and custom XML/JSON objects somehow in one request in ONE wrapper object.
(It works with one wrapper object annotated #Form and the other parameter to be without #Form annotation, but I would like to have all in one wrapper object).
Thank you for any insights or help.
You are mixing JAX-RS and JAXB annotations. That's a bad idea. Use JAX-RS annotations on resource classes and JAXB annotations on represenation classes.
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