jackson empty query param behavior - java

I am working in a REST service using javax.ws.rs, running under Glassfish, and I have some strange behavior differences on different servers, regarding the interpretation of empty query params.
Note, actual names of services and implementation details deemed unimportant have had their names changed or been omitted, to protect the innocent.
Some (most) servers treat a request
http://localhost/serviceRoot/orders?status=
(i.e. a query param named status is provided, but with no value after the = sign) as equivalent to
http://localhost/serviceRoot/orders
essentially letting that query param be null, but some treat it as though that query param had the value of "" (empty-string).
This is a problem in my case, because:
/* In a Resource class, I have this method defined: */
#GET
#Path("/orders")
public Response getOrders(#QueryParam("status") OrderStatus orderStatus) throws Exception {
/* code to pull orders, optionally by status, and return them in a Response */
}
/* ... and elsewhere, our enum */
public enum OrderStatus {
RECEIVED, ACKNOWLEDGED, CANCELLED
}
and when someone sends the first request above to a server which treats it as an empty string, I get an error in the form:
"java.lang.IllegalArgumentException: No enum constant com.fqcn.OrderStatus."
(because "" is not a valid value in the enum which it tries to automatically construct) whereas it would successfully retrieve a list of orders, if the request hit a different server.
In order to debug, though I was not able to make it produce a stack trace under normal execution, I was able to write an ExceptionMapper, and output the stack trace of that, explicitly, so I came up with this:
com.sun.jersey.server.impl.model.parameter.QueryParamInjectableProvider$QueryParamInjectable.getValue(QueryParamInjectableProvider.java:74),
com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203),
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75),
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339),
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708),
javax.servlet.http.HttpServlet.service(HttpServlet.java:770),
org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550),
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281),
org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:175),
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java),
org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655),
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595),
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161),
org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331),
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231),
com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317),
com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195),
com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860),
com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757),
com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056),
com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229),
com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90),
com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79),
com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54),
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59),
com.sun.grizzly.ContextTask.run(ContextTask.java:71),
com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532),
com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513),
java.lang.Thread.run(Thread.java:724)
My problem is: I do not know where this query-param interpreting behavior resides (what config file, or class/jar file), and I do not have control over the clients requesting this. Furthermore, the "big red button" approach of taking down the offending servers and standing up new clones from a "known good" instance is time-expensive and has to be done very carefully.
The question I would like answered is: Where, if anywhere within Glassfish or Jackson (or another layer of the service stack?), is this empty-query-param interpreting behavior configured, and how do I change it?

Related

Filtering by machine type in GCP

I'm trying to filter the list of instance based on the machine type. However this doesn't seem to work.
Compute.Instances.List request = computeService.instances().list("project-name","us-central1-a" );
request.setFilter("(machinetype = zones/us-central1-a/machineTypes/n1-standard-1)");
InstanceList instanceList = request.execute();
List<Instance> instances = instanceList.getItems();
The response is empty even though, I have an instance that match the filter! (when I remove the filter it gets the instance.)
[chaker#cbenhamed:~]$ gcloud compute instances list
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
foo-bar-worker-n1-standard-1-65304152130-zfq us-central1-a n1-standard-1 true 10.240.0.2 00.000.00.255 RUNNING
According to the documentation, the filter parameter should work in this case. Because, first the machineType is in the root of the Instance object. And second that's the right form of the machineType argument
Full or partial URL of the machine type resource to use for this instance, in the format: zones/zone/machineTypes/machine-type. This is provided by the client when the instance is created.
I tried to inspect HTTP requests made by gcloud
gcloud compute instances list --filter="machineType:n1-standard-1" --log-http
But it turned out that it gets the whole list (across all zones!) and filter them locally!
It seems to be a misunderstanding, the documentation describes the machineType as an argument of the Response body no as a filter. So in this case you can't use a partial URL also you can only use the following comparison operators =, !=, >, or < which none of them works as a like.
I think the only way to use this filter is using the full URL just as Oleksandr Bushkovskyi commented:
machineType="https://www.googleapis.com/compute/v1/projects/[PROJECT]/zones/[ZONE]/machineTypes/[MACHINE_TYPE]"

Simple GET request with Facebooks API

I am currently taking a course in app development and I am trying to use Facebooks API for GET requests on certain events. My goal is the get a JSON file containing all comments made on a certain event.
However some events return only a an "id" key with an id number such as this:
{
"id": "116445769058883"
}
That happends with this event:
https://www.facebook.com/events/116445769058883/
However other events such as (https://www.facebook.com/events/1964003870536124/) : returns only the latest comment for some reason.
I am experementing with facebook explore API:
https://developers.facebook.com/tools/explorer/
This is the following GET requests that I have been using in the explorer:
GET -> /v.10/facebook-id/?fields=comments
Any ideas? It's really tricky to understand the response since both events have the privacy set to OPEN.
Starting from v2.4 of the API, the API is now declarative which means you'll need to specify what fields you want the API to return.
For example, if you want first name and second name of the user, then you make a GET request to /me?fields=first_name,last_name else you will only get back the default fields which are id and name.
If you want to see what fields are available for a given endpoint, use metadata field. e.g. GET /me?metadata=true

Creating a filter to check a case for a letter in a field in the json body in REST assured

I have a request in the form of json,which looks like this.
{"User":{"email":"test#test.com","FName":"fname"}}
When I try to send it via REST assured ,the U in the User is seen to change its case.i.e. changes to a lower case.
To send the request I have created my own serialized classes. The end-point is seen like this:
{"user":{"email":"test#test.com","FName":"fname"}}
but somehow it is not changing the case of the remaining fields.I don't knwo why this is happening.
I've even tried to create a filter for a request specification,but couldn't go any further with that too. I also then thought of first converting the serialized object to a gson,and then check the case of the User, still no luck.
Error I get is:
The class, User,does not match the payload object for payload.
Please note I am trying to use the service of another team,so I really don't have an access to their code-base(Although not needed).Observe the space between the first , and user in the above message, is it worth noting?
I finally got away with it by converting the object(JSON) into a JSON string/payload.
And while passing it as a form parameter,passed the string/payload.
Somehow,still couldn't figure out why the formparameter/formparam option in RESTAssured did not allow the serialized object to go through. But,anyway got around it this time.
Thanks for the suggestions all.

Drools render output in a webpage

I'm new to Drools Expert, currently from the Sample project of the drools what I can only do is print something to the console. Now I integrate drools to a web project and It was successful, I was be able to print something to the console depending on the interaction of the user to the page.
My rules currently is like this:
rule "A test Rule"
when
m: FLTBean ( listeningScore == 1, test : listeningScore )
then
System.out.println( test );
end
So what if I want to print it out to a web page? How would I do that? Do I need to use return to return some value back to the java page and render it to the page?
In order to display something on a web page, then you need to be using the API to invoke Drools and get some output, which can then be rendered by your web application.
Therefore, you need to consider how to get output from it within your Java code. There are a few ways of doing this.
For example, when performing a simple action such as validating a request, then just operate on the request which you insert. For instance:
rule "IBAN doesn't begin with a country ISO code."
no-loop
when
$req: IbanValidationRequest($iban:iban, $country:iban.substring(0, 2))
not Country(isoCode == $country) from countryList
then
$req.reject("The IBAN does not begin with a 2-character country code. '" + $country + "' is not a country.");
update($req);
end
In that example, I'm calling a "reject" method on the fact which I inserted. That modifies the inserted fact, so that after rules execution, I have an object in my Java code, with a flag to indicate whether it was rejected or not. This method works well for stateless knowledge sessions. i.e.
Java code - Insert request fact via API
Drools rule - Modify the request fact (flag rejection, annotate, set properties, etc)
Java code - Look at the fact to see what was done to it
The following code example of how to perform this interaction is taken from the following full colass:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/payments/validation/payment/RuleBasedPaymentValidator.java
// Create a new knowledge session from an existing knowledge base
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
// Create a validation request
PaymentValidationRequest request = new PaymentValidationRequest(payment);
// A stateless session is executed with a collection of Objects, so we
// create that collection containing just our request.
List<Object> facts = new ArrayList<Object>();
facts.add(request);
// And execute the session with that request
ksession.execute(facts);
// At this point, rules such as that above should have been activated.
// The rules modify the original request fact, setting a flag to indicate
// whether it is valid and adding annotations to indicate if/why not.
// They may have added annotations to the request, which we can now read.
FxPaymentValidationResult result = new FxPaymentValidationResult();
// Get the annotations that were added to the request by the rules.
result.addAnnotations(request.getAnnotations());
return result;
An alternative in a stateful session would be that rules could insert facts into working memory. After executing the rules, you can then query the session via the API and retrieve one or more result objects. You can get all facts in the session using the getObjects() method of the KnowledgeSession. To get facts with particular properties, there is also a getObjects(ObjectFilter) method. The project linked below has examples of using these methods in the KnowledgeEnvironment and DroolsUtil classes.
Alternatively, you could insert a service as a global variable. The rules could then invoke methods on that service.
For an example of how to use Drools within a web application, I knocked up this web site recently, which provides a REST API to invoke Drools rules and get responses.
https://github.com/gratiartis/sctrcd-payment-validation-web
If you have Maven installed, you should be able to try it out pretty quickly, and play around with the code.

Handling multiple parameters in a URI (RESTfully) in Java

I've been working on a small scale web service in Java/Jersey which reads lists of user information from clients contained in XML files. I currently have this functioning in all but one aspect: using multiple parameters in the URI to denote pulling multiple sets of user information or multiple sets of client information. I have a version which currently works, but is not the best way nor what the project description calls for.
Currently, my code looks like this:
#Path("Client/{client}/users")
public class UserPage
{
#GET
#Produces(MediaType.TEXT_HTML)
public String userChoice(#PathParam(value = "client") final String client)
{****Method here which handles a list of 'users'****}
#GET
#Path("{name}")
#Produces(MediaType.TEXT_HTML)
public String userPage(#PathParam(value = "client") final String client, #PathParam(value = "name") final String name)
{****Method here which handles 'user' information****}
The first method handles a list of users from a 'client' denoted by "{client}" in the URI. The second method delivers 'user' information denoted by "{name}" in the URI. Both will function with a single argument. Currently, in order to handle multiple 'users' I have "{name}" comma separated like "Client/Chick-Fil-A/users/Phil,Bradley". I can parse this after using #PathParam and create an array of these 'users', but again, I feel this is not the best way to handle this, and the project description calls for something different.
Is there a way to accomplish this same task with a URI formatted as "Client/Chick-Fil-A;cd=Phil,Bradley"? (The ;cd= is what's giving me the most trouble.)
I also need to be able to use this format for multiple clients, i.e. "Client;cd=Chick-Fil-A,Subway/users;cd=Phil,Bradley".
Edit: To clarify the project:
The client information is contained in 6 separate files. Each of these files has the same 3 users (this is a proof of concept, effectively). I need to be able to pull different subsets of information, for instance, user Phil from McDonalds and Chick-Fil-A, or users Phil and Peter from McDonalds, or users named Peter from all clients, etc.
You cannot use '=' in the URL path since it's a reserved character. However there are many other character you can use as delimiters such as '-' and ','. So instead of '=' you can use '-'. If you really really want to use '=' then you will have to URL-encode it; however, I would strongly recommend against this because it may make things more complicated then it should be.
You can see the grammar of the URL string here:
http://www.w3.org/Addressing/URL/url-spec.txt
Copy and search the following string to skip to the path grammar:
path void | segment [ / path ]
segment xpalphas
That said, I believe HTTP request is usually used for request single resource only. So my personal opinion is to not implement the service the way you implemented. For getting multiple clients I would use query parameters as filters like this:
Client/{cName}/users?filters=<value1>,<value2> ...
Edit: From the business case you got there, it seems like you probably need service like
/users?<filters>
/clients?<filters>
So say you want to get Peter from all clients then can have a request of this form:
/users?name=Peter
Similarly, if you want to get Jack and Peter from Starbucks then you can do:
/users?name=Peter,Jack&client=Starbucks
Hopefully this helps.
Query strings have the following syntax and you can have multiple parameters with the same name:
http://server/path/program?<query_string>
where query_string has the following syntax:
field1=value1&field1=value2&field1=value3…
For more details check out this entry in Wikipedia: http://en.wikipedia.org/wiki/Query_string

Categories

Resources