Jersey REST service: Detect if URL ends with a questionmark - java

Detecting Questionmarks
I need to implement a protocol where the user may provide a question mark appended to an URL in oder to retrieve additional information about the provided resource. I am aware that the questionmark after the URL resource indicates query parameters. Unfortunately this protocol does demand question marks at the end of the URL as an indicator.
Implementation
I implemented the service using Jersey.
#GET
#Path("{/service/")
#Produces(MediaType.TEXT_PLAIN)
public String resolve(#PathParam("uri") String fqn,
#PathParam("ark") String arkLabel,
#Context UriInfo ui, #Context HttpServletRequest hsr) {
// here i need to test of the url ends with ?
if (url.endsWith("?")) {
// to something
}
}
The Problem
All the methods provided from UriInfo and HttpServletRequest i found stripe away the last questionmark, if it is not followed by a query parameter. How can I get the raw URL, including a question mark at the end?
Solution
Based on the answer from #cy3er I could solve the problem. The following snipped does the trick. The method getQueryString() returns null if the URL did not contain any query, i.e. if there was no ? attached to the URL. Then I can assume if the string is empty, that there was only one ?, because the query is empty. In the third caswe I can check if the only query parameter passed is one ?, which corresponds to two ?? in the URL.
if (hsr.getQueryString() == null) {
this.logger.info("Normal link");
} else if (hsr.getQueryString().equals("")) {
this.logger.info("one ?");
} else if (hsr.getQueryString().equals("?")) {
this.logger.info("Two ??");
} else {
this.logger.info("None of the above");
}

Use the getQueryString method of the HttpServletRequest, if it's null there wasn't any questionmark.
See documentation

Related

Performing validation using a custom annotation and returning a Response with HTTP error code

I am currently working with Java EE and I have a requirement to validate a field using a custom annotation and if it's valid, do nothing, but if it's not, then return a response. Let me explain it in a bit more detail below.
Firstly I have this Enum called Weekday.
public enum Weekday {
Monday("monday"),
Tuesday("tuesday"),
Wednesday("wednesday"),
Thursday("thursday"),
Friday("Friday),
Saturday("saturday"),
Sunday("sunday");
private final String value;
Weekday(String value) {
this.value = value
}
}
Then I have this request that accepts a weekday. Now I want to check if the weekday value is either Monday or Tuesday, if it's not then I want to respond with the HTTP error code 400 Bad request instead of proceeding with processing the request.
#Path("/dosomething")
#GET
public Response doSomething(#QueryParam("weekday") Weekday weekday) {
return Response.ok().build();
}
I want to create a #ValidateWeekday annotation for the field which will validate it and send an Error 400 response.
My first approach involved using if-else then a switch case, but that is not clean looking. I want to do it using a custom annotation.
if (weekday =! Weekday.Monday && weekday != Weekday.Tuesday) {
return Response.status(400).build();
}
This is a bad practice and I want to avoid this.
What I want is something like this.
#Path("/dosomething")
#GET
public Response doSomething(#QueryParam("weekday") #ValidateWeekday Weekday weekday) {
return Response.ok().build();
}
So, how do I go about doing this by making my own #ValidateWeekday annotaion ?
In Spring we can simply use #ControllerAdvice and #ExceptionHandler annotations, but I'm not using Spring so I have to build my own annotations that can achieve this.

How can I make use of the value returned from my API that is expressed in Collections.singletonMap?

Basically, I'm trying to update the attribute "subscribed_status" from one of the entities when the API is called. When the attribute gets patched/updated successfully or unsuccessfully in my java server, I will get a message in the frontend console accordingly, expressed in the following form due to the use of Collections.singletonMap:
{response: 'FAILURE'},
{response: 'SUCCESS'}
The question is when I get this from the backend, how I can set conditions like the following in my Reactjs?
//The condition doesn't work because data is not string. I'm not even sure
if(res.data==='FAILURE'){
//execute some sorts of command
}
For a better understanding of what my backend returns to my frontend, the following is provided for review:
#PatchMapping("/updateSubscribedStatus/{email}")
public Map<String, String> updateSubscribedStatus(#PathVariable String email) throws AlreadySubscribedException {
try{
Boolean updateStatus=userService.updateSubscribedStatus(email);
if(updateStatus){
return Collections.singletonMap("response", "SUCCESS");
}
return Collections.singletonMap("response", "FAILURE");
}catch(Exception alreadySubscribedException){
return Collections.singletonMap("response", "FAILURE");
}
}
In my frontend, I am using axios to call the API and invoke a function on the condition that I get {response: 'FAILURE'}:
export const updateSubscribedStatus=(email:string,setSubscribedStatus:(subscribedStatus:boolean)=>void,toggleShowAlreadySubscribedError:()=>void)=>{
axios.patch(`http://localhost:8080/user/updateSubscribedStatus/${email}`)
.then((res)=>{
console.log(res.data);
setSubscribedStatus(true);
// The following if statement is where I get stuck
if(res.data.toString()==="FAILURE"){
toggleShowAlreadySubscribedError();
}
}).catch((error)=>{
console.log(error);
setSubscribedStatus(false);
})}
I will appreciate your help! Thanks a million in advance!
Without knowing much about axios, it looks to me that res.data will be the full payload, so I expect res.data.response to contain your "FAILURE" string.
Moreover, I do think the correct RESTFul way to implement would be to
return "HTTP 200 OK" in case of success and an "HTTP 40x" (say HTTP 409) in case of already subscribed.
You can achieve this by putting a ResponseEntity<?> as a return type of your #PathMapping method and returning the correct code.
public ResponseEntity<?> updateSubscribedStatus(...) {
try {
...
return new ResponseEntity<Success>(HttpStatus.OK);
} catch (..) {
return new ResponseEntity<Error>(HttpStatus.CONFLICT);
}
}

How do I differentiate between an optional value that was not passed and an explicit value in JSON?

I'm having problems differentiating between an optional value that was not passed and an explicit value in a JSON request.
The problem is that buildLevel and securityClass are defined as int fields in gmxClient.java, so when I POST a JSON object that does not contain one of the fields it is read as 0 and the value gets overwritten.
For example, if buildLevel = 3 and securityClass = 1 and this is my JSON request, securityClass gets overwritten as 0:
{
"id"=00039281,
"buildLevel"=5
}
Is there any way to get around this?
.
.
.
.
gmxClientFacadeREST.java:
#POST
#Path("{clientId}")
#Consumes({MediaType.APPLICATION_JSON})
public Response editPost(#PathParam("clientId") Long clientId, gmxClient old) {
try {
gmxClient new = super.find(id);
new.update(old);
super.edit(new);
return Response
.status(Response.Status.OK)
.build();
}
catch (Exception e) {
return Response
.status(Response.Status.BAD_REQUEST)
.build();
}
}
gmxClient.java:
public void update(gmxClient newEntity) {
if (newEntity.getBuildLevel() != null) setBuildLevel(newEntity.getBuildLevel()); // Throws exception, int will never be null
if (newEntity.getSecurityClass() != null) setSecurityClass(newEntity.getSecurityClass()); // Throws exception, int will never be null
}
For reasons like this (and many others) it's good idea to have separate classes for a DTOs (used to contain data in transit - i.e. when sent to external service / to database / received through http request body) and separate classes used in the business logic in your application.
You face this problem because you used the same class for both a) http request body and b) business domain logic. Due to that your business model class gmxClient liminations (securityClass and other fields being primitives that can't express "lack of value") are also limiting your layer that integrates with "outside world" - in your case: your controller.
So, what I'd suggest you to do is to: create new class that will be used only within the controller (as request body), in this class you can use Integer, that will of course have a value of null when parsed from json - in case it doesn't exit.
Then in the following logic you decide how to map it into your business model object.

Play Framework 2 + java does not return URL dynamic part in getQueryString call

This may be a duplicate question but I was not able to find a solution. As a result, I'm posting my own one.
My URL looks like this "/customer/www.bakeryx.com" where www.bakeryx.com is the URL dynamic part and maps to "/customer/:domain".
I was hoping that when I call ctx.request().getQueryString("domain") I would get the www.bakeryxcom. Otherwise, I get a null response and there is no way to get this value from the action.
Please find bellow my work around for this task. I had to get the ROUTE_PATTERN from the context args.
public class DomainVerifierAction extends Action<DomainVerifierFilter> {
#Override
public Result call(Http.Context ctx) throws Throwable {
//how to get the domain here??
//work around is to get the route_pattern
String routePatternPlay = (String) ctx.args.get("ROUTE_PATTERN");
String path = ctx.request().path();
//added logic to extract domain from the PATH using ROUTE_PATTERN.
}
}
Question: Is there any solution for this problem?
I think the problem you are having is that the getQueryString method you are using is looking for the "?" operator in the URL, as in a traditional GET request (e.g. ?id=1). Instead, try passing the domain as a parameter in the controller method. For example:
In your routes file:
GET /customer/:domain controllers.Application.function(domain: String)
Then in your Play controller (assuming Play Framework 2.x):
public static Result function(String domain){
//Do something with the passed domain string here
return ok(...);
}

Optional path variables in Spring-MVC RequestMapping URITemplate

I have the following mapping:
#RequestMapping(value = "/{first}/**/{last}", method = RequestMethod.GET)
public String test(#PathVariable("first") String first, #PathVariable("last")
String last) {}
Which for the following URIs:
foo/a/b/c/d/e/f/g/h/bar
foo/a/bar
foo/bar
maps foo to first and bar to last and works fine.
What I would like is something that maps everything between foo and bar into a single path param, or null if there is no middle (as in the last URI example):
#RequestMapping(value = "/{first}/{middle:[some regex here?]}/{last}",
method = RequestMethod.GET)
public String test(#PathVariable("first") String first, #PathVariable("middle")
String middle, #PathVariable("last") String last) {}
Pretty stuck on the regex since I was hoping that something simple like {middle:.*}, which only maps to /foo/a/bar, or {middle:(.*/)*}, which seems to map to nothing.
Does the AntPathStringMatcher tokenize upon "/" prior to applying regex patterns? (making patterns that cross a / impossible) or is there a solution?
FYI this is in Spring 3.1M2
This seem similar to #RequestMapping controllers and dynamic URLs but I didn't see a solution there.
In my project, I use inner variable in the springframework:
#RequestMapping(value = { "/trip/", // /trip/
"/trip/{tab:doa|poa}/",// /trip/doa/,/trip/poa/
"/trip/page{page:\\d+}/",// /trip/page1/
"/trip/{tab:doa|poa}/page{page:\\d+}/",// /trip/doa/page1/,/trip/poa/page1/
"/trip/{tab:trip|doa|poa}-place-{location}/",// /trip/trip-place-beijing/,/trip/doa-place-shanghai/,/trip/poa-place-newyork/,
"/trip/{tab:trip|doa|poa}-place-{location}/page{page:\\d+}/"// /trip/trip-place-beijing/page1/
}, method = RequestMethod.GET)
public String tripPark(Model model, HttpServletRequest request) throws Exception {
int page = 1;
String location = "";
String tab = "trip";
//
Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
if (pathVariables != null) {
if (pathVariables.containsKey("page")) {
page = NumberUtils.toInt("" + pathVariables.get("page"), page);
}
if (pathVariables.containsKey("tab")) {
tab = "" + pathVariables.get("tab");
}
if (pathVariables.containsKey("location")) {
location = "" + pathVariables.get("location");
}
}
page = Math.max(1, Math.min(50, page));
final int pagesize = "poa".equals(tab) ? 40 : 30;
return _processTripPark(location, tab, pagesize, page, model, request);
}
See HandlerMapping.html#URI_TEMPLATE_VARIABLES_ATTRIBUTE
Can't be done as far as I know. Just as you stated, the regular expression is being applied to the path element after splitting up the path at each slash, so the regular expression can never match a '/'.
You could manually inspect the url and parse it yourself from the request object.
It could be done by writing a custom path matcher and configuring Spring to use it. For example, such a solution is documented here: http://java.dzone.com/articles/spring-3-webmvc-optional-path
The link provides a custom path matcher and shows how to configure spring to use it. That should solve your need if you don't mind writing a custom component.
Also, this is a duplicate of With Spring 3.0, can I make an optional path variable?
try to use this
#RequestMapping(value = {"some mapped address","some mapped address with path variable","some mapped address with another path variable"})
array list of available url for specific method
But be careful on creating list of url when you are using #PathVariable in your method signature it cant be null.
hope this help

Categories

Resources