I'm new to java / rest / jersey, so please bear with me.
Problem: I want to use a GET method to retrieve some information I have previously POSTed. My only confusion is...where is the information after I call the GET?
Here is my post (you can ignore it as I know this part works):
#POST #Path("/tools")
public Response createTool(JsonNode tool) throws URISyntaxException {
//use custom validator to de-couple implementation from validation
ToolValidator validator = new ToolValidator(tool);
if(validator.isNotNull() == false) {
System.out.println("in not null");
return Response.status(400).entity("Please add tool details").build();
}
if (validator.hasValidType() == false) {
System.out.println("in valid timestamp");
return Response.status(400).entity("Please provide a valid tool type").build();
}
if(validator.haveValidValues() == false ) {
System.out.println("in valid values");
return Response.status(400).entity("Please provide a tools list with valid numerical values").build();
}
String type= tool.get("type").asText();
return Response.status(201).entity(tool).build().created(new URI("/tools/"+type)).build();
}
It definitely posts a tool correctly (I've tested it and seen it, I believe this works but it might not).
Now what I want to do is get the json, see if adheres to some requirements, and return an answer. Basically, irrelevant of the POST code above, for any url that returns some json when you navigate to it, I want to be able to grab that json and do something with it.
#GET #Path("/tools/{type}")
public Response getToolInfo(#PathParam("type") String type) {
return Response.ok().build();
}
My only question here is..."where" is the information to manipulate?? I feel like I'm asking an extremely fundamental, basic question for REST / Jersey, so I apologize if this is like the ABCs here.
Basically, I use my POST method to POST a tool with some specific json. I can navigate to that page and see the json object. Now I want to use a GET method to analyze the json but...I have no idea how / where this information is stored when I decide to use a GET method.
Does the #get annotation automatically store the information returned from the specified path somewhere? Does anything?
From the code you pasted it doesn't look like anything is stored. In your #POST it looks like you pass JsonNode tool, from that you create an object of type ToolValidator which you use to do some sort of validation. From your JsonNode tool you retrieve a field called "type".
At last you create a response instance with the parameter you already passed and you change the Uri to "/tools/" and the String value of whatever is in the variable "type".
So it doesn't look like you are doing any database access to store the JsonNode passed as parameter.
It definitely posts a tool correctly (I've tested it and seen it).
It posts the tool because of this Response.status(201).entity(tool).build()
You are just simply telling it to set the response entity in the builder. Whereas build() a response instance.
For testing purposes only create a global variable, in your class, of type JsonNode and copy the passed parameter (JsonNode tool), in your POST method, to your global variable. Then you can retrieve it in your GET method. Don't forget to create getter and setter for your global variable.
In a real life scenario though you would be storing things in your database. If it's just for some prototype then a global variable should be enough
Here is a tiny example of what I mean:
public class SomeClass {
private JsonNode copiedTool;
#POST #Path("/tools")
public Response createTool(JsonNode tool) throws URISyntaxException {
setCopiedTool(tool);
String type= tool.get("type").asText();
return Response.status(201).entity(getCopiedTool()).build().created(new URI("/tools/"+type)).build();
}
#GET #Path("/tools/{type}")
public Response getToolInfo(#PathParam("type") String type) {
if(getCopiedTool().get("type").equals(type)) {
return Response.ok(getCopiedTool()).build();
}
return Response.status(204).build();
}
public JsonNode getCopiedTool() {
return copiedTool;
}
public void setCopiedTool(JsonNode copiedTool) {
this.copiedTool = copiedTool;
}
}
Related
I recently stumbled upon a problem that I could not find any references to although it's very unlikely nobody ever had this problem before.
Maybe someone can give me a heads-up on where to look.
Using JAX-RS to build a REST service running on JakartaEE 8 I created a method that's supposed to handle PUT requests from the client. This method is given a DTO object which, amongst other things, contains a HashMap that uses Long variables as keys.
This works just fine so far and the method accepts the input given by the clients PUT request.
However when I check for the type of the variables that the keyset() method return for the HashMap it is not of type Long but instead of type String which obviously leads to problems later on.
Here is a shortened version of the code in question:
#PUT
#Path("edituser")
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Optional<DTOobject> editUser(#QueryParam("user_id") Long user_id, DTOobject dto_object) {
for (Object i : dto_object.getOtherDTO_map().keySet()) {
LOGGER.log(Level.INFO, "HashMap key of type: {0}", i.getClass().getName());
// This will return java.lang.String as the type for the individual keys.
}
// do something and return something
}
public class DTOobject {
// some other vars
private HashMap<Long, OtherDTO> otherDTO_map;
// getters and setters
}
I have a question about best practices. Let's say I have a web method that returns employee id and employee name. Now, since I am new to Web Service, we( client(C#) and I(Java)) agreed upon a return type List<String> and String format is employee id,employee name. All is well so far. Program runs and it does the job.
Now, the other day, I was having conversation about return type with another developer and she suggested the way I am returning the data is not right instead I should return String in XML format so the typical output may look like (here without formatting),
<root><employee><employeeId>1234</employeeId><employeeName>firstname lastname</employeeName></employee></root>
I argued that, in this case, you're returning more than 50% non-data(XML tags) to client which is unnecessary and waste bandwidth and increase overhead. And she argued back that in case of unobvious scenarios like, user does not have permission to access something or there is nothing to return but the error code or something went wrong on server i.e when you need to return something else other than actual data itself, XML string is helpful since you can insert tag. And it's a valid argument so can somebody with good experience with Web Service shed some light here?
Basically when your list is serialized it will be converted to XML although the format would be like:
<Value>EmployeeId, EmployeeName</Value>
The tags are not actually unneccessary and in fact they are helpful as they preserve the data and it's conctrete data type. I am not fan of returning an XML string as it is prone to error and you may always need to update the value of the string. What I suggest is to return an object containing your result set and an error description property.
public class ReturnObject
{
public List<Employee> list {get; set;}
public String ErrorDescription {get; set;}
}
public class Employee
{
public int EmployeeID {get; set;}
public string EmployeeName {get; set;}
}
In here your web service will return a concrete type with additional property 'ErrorDescription' that you can use if you need to return any validation or authentication errors. Use SoapUI to test that serialized return object is XML.
My service:
#POST
public String setData(#QueryParam("id") Long is, MyObject payload) {
...
}
or
#POST
public String setData(#PathParam("id") Long is, MyObject payload) {
...
}
My interceptor on the server:
Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException {
Class mypayloadtype = context.getType;
InputStream mypayloadinpustream = context.getInputStream();
Long myidparam = ???????? // how to get the query or path param here?
}
EDIT: To be a bit more concrete:
What I'd like to do is to grab the XML and store it based on the parameters in a separate audit system. Maybe PreProcessInterceptor / PostProcessInterceptor are the better choices?
Any hints or alternative ways to get the param when the xml is still available for preprocessing?
Miguel
I just stumbled over the same problem today. I needed the #PathParams and #QueryParams in the read() method and ended up with something like this:
public class MyInterceptor implements PreProcessInterceptor, MessageBodyReaderInterceptor
{
private static ThreadLocal<UriInfo> uri = new ThreadLocal<UriInfo>();
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
{
uri.set(request.getUri);
...
}
public Object read(MessageBodyReaderContext context)
{
String param = uri.get().getPathParameters().getFirst("myidparam");
...
}
}
Although when thinking about it now - I'm not quite sure, if just using PreProcessInterceptor/PostProcessInterceptor will also do the trick for my (and maybe your) problem. I'll have another look tomorrow.
I am not an expert on the topic but to me it seems as if the MessageBodyReaderContext interface does not really know if it is on the server or the client side, so it cannot expose the request or its parameters / path parts etc.
So as far as I know this is not possible.
If your code knows that it lives on the server side of the rest
communication, maybe you can use a servlet filter to store the request
in a ThreadLocal and then access it from there while the request is
handled, somewhat similar to RequestContextFilter / RequestContextHolder from the spring framework? (Then the request object does not know anything about the annotations of your service, but instead one has to extract the information manually from the request. This means to have the same information in two places, so there has to be a better solution ...)
Edit: after looking at some examples I get the vague feeling that if you want to read the input stream to create an object and add path parameters to it, MessageBodyReaderInterceptor is simply not the way to go. Instead set up a MessageBodyReader which constructs the object from the request body data, and this then will be passed into the public String setData(#PathParam("id") Long is, MyObject payload), assuming that this method is annotated with a #Consumes which matches the #ConsumeMime annotation for the MessageBodyReader. There you might be able in the setData to set the missing id on the object read from the request body. Some examples related to this seem to be here: How to get full REST request body using Jersey? (but for Jersey, not jBoss :-/)
However I am not sure if that works for you, and I also feel I completely overestimated my ability to answer this question appropriately, so I hope someone more knowledgeable comes in with a better solution.
I have a controller with a method that handles incoming GET data, stores some things in the model, and then redirects to another page that deals with these objects.
I can't seem to find any good way of getting the object stored in the first method back out of the model to use in the second method. How can I do this?
Here's the top of the controller:
#Controller
#RequestMapping("/reviews")
#SessionAttributes({"review", "externalReview"})
public class ReviewController {
// [SNIP]
}
Here's the code that adds the objects I'm after to the model:
#RequestMapping(value="/new", params="UName", method=RequestMethod.GET)
public String newFormFromExternal(#ModelAttribute("externalReview") ExternalReview externalReview, Model model) throws IncompleteExternalException {
// Convert the inbound external
Review fromExternal = ExternalReviewUtil.reviewFromExternalReview(externalReview, externalDAO);
// Add the externalReview to the session so we can look to see if we got a reviewee on the way in
model.addAttribute("externalReview", externalReview);
model.addAttribute("review", fromExternal);
return "redirect:/reviews/newFromExternal";
}
You are in luck.
If you are using or have ability to update to the newly released Spring 3.1, you can make use of the newly scoped Flash variables.
http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/mvc.html#mvc-flash-attributes
If you can't use 3.1, you probably can implement the solution yourself. Essentially you want to capture the model object required to be present in the redirect, put in the session, and remove it once it is retrieved to keep your session from bloating.
Currently, I'm just getting a Map of the model, getting the object I want out by it's key (the String name), and then casting it to the object it really is (rather than just Object).
Here's the code:
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(Model model) {
// Get the review from the model
Review review = (Review) model.asMap().get("review");
/*** Do stuff with the review from the model ****/
return "reviews/newFromPacs";
}
This way works, but it seems hacky and clunky. Is this really the only way?
One possible solution is to use #ModelAttribute, though it's quite ugly since you'll need to disable databinding for that attribute (for security):
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(#ModelAttribute Review review) {
...
}
#InitBinder("review")
public void disableReviewBinding(WebDataBinder b) {
b.setAllowedFields();
}
Is there's a way to get the value returned by a java controller method in javascript in the views ?
what I want to do is:
i'm in view showX rendered by controller method X.show()
i want to create an object y so $.post('#{Y.create()}')
now i need the id of the created object of type y to use it in the same view (showX).
is that possible?
It sound like what you need (although your question is very vague), is to return JSON from your controller method.
Such as, in your controller, you can do
public static void myActionOne() {
renderJSON(myObject);
}
And then you will call myActionOne from your javascript using $.post. I would also suggest looking at the Play jsAction tag if you are not already using it. This will return a JSON representation of the object. You can then take whatever information you need and call a second action in the same way.
Again, in the second action, I would suggest jsAction, as it makes passing parameters into your actions far easier.
EDIT:
Based on your edit, then all you need to do is in your controller method Y.create, do something like
public static void create() {
MyObject obj = new MyObject();
obj.save();
Long id = obj.id;
renderJSON(id);
}
Obviously your code to create your object will be different, but you get the idea. You can then just take the data from the JQuery post response, and access the id that has been returned, using standard javascript.
You question is too vague. But you probably will need of AJAX to get a value of this kind.
Take a look here: http://www.oracle.com/technetwork/articles/javaee/ajax-135201.html