How to get resource link for pagination in katharsis - java

I'm trying to do pagination. What I have works, but I have some doubts about the way I get a Resource URL.
In my Resource Repository, I inject a ResourceRegistry in a Lazy way (I know it's a circular dependency) to get a URL for my Resource that I then use to generate my links.
String resourceUrl = resourceRegistry.getResourceUrl(Book.class);
It works fine, but the circular dependency bothers me. Is there some static class to get a resource URL. Or perhaps there's a completely different way of approaching this?

Maybe this is not a satisfying answer, but katharsis does generate links in it's serializers. You could probably extend one of the katharsis' serializers and make it aware of optional meta information, containing the total number of items available, which the client would need to know anyway. From this data, you could create the top level links for prev and next pages. In the katharsis serializers the resourceRegistry will be available anyway, along with QueryParams, containing the original pagination parameters.
This is all very hypothetical though.
The suggested solution by katharsis devs would be:
#JsonApiFindAll
public JsonApiResponse findAll() {
return new JsonApiResponse()
.setEntity(Collections.singletonList(new Task(1L, "John")))
.setLinksInformation(new LinksInformation() {
public String self = "...";
public String first = "...";
public String prev = "...";
public String next = "...";
public String last = "...";
});
}
Taken from here:
https://github.com/katharsis-project/katharsis-core/issues/307
https://github.com/katharsis-project/katharsis-core/issues/328
Still, hand-crafting the links seems required.

Related

Spring MVC : Generating links which match the controller url pattern

I am writing a web app with Spring 4.0.
I have written my controllers in what I believe to be the normal way using the #RequestMapping annotation to define the url pattern which the controller handles.
The snippet below illustrates this for a controller which displays a testimonial ...
#Controller
#RequestMapping("/testimonialView")
public class TestimonialRequestController {
#RequestMapping(value="/{testimonialName}", method=RequestMethod.GET)
public ModelAndView testimonialRequest(#PathVariable String testimonialName, ModelAndView modelAndView) throws FileNotFoundException {
Testimonial testimonial;
. . .
}
}
Elsewhere in my application I want to generate a link bar which includes all the testimonials to include in my left hand nav.
At the moment, when I construct the href for the anchor element to go into the link bar, I am hardcoding the url, like this:
String href="/testimonialView/" + testimonialName;
This does not seem right. If later on I want to change the url structure I have to change it in at least two places - possibly more. Once where the incoming URL is matched to the controller, and once to construct the anchor element which a user will click to invoke that URL.
Is there a best practice way of dealing with this problem? It must be a common one. Is it as simple as using Constants to represent the URLs and accessing these from different places? I know my example is simple but I am assuming the problem must exist for much larger web apps with complex URL structure so I want to understand what best practice is.
I hope this isn't a stupid question. I am keen to ensure that I implement best practice right from the beginning. I have looked through Stackoverflow and Google but nothing quite answers this specific question.
Any help gratefully received.
The short answer is that you can't do this dynamically because #RequestMapping puts data into the code at compile time.
However, there are a couple of options that work.
You can define the string constants in a separate class - this will make it easier for you to change the names of URLs
You can explore the request mappings at runtime within Spring, so could have some code that found URLs you'd coded elsewhere - I've done this for identifying when a URL is dynamic content, vs coded content.
My recommendation is
public class URLs {
public static final String TESTIMONIAL_VIEW = "/testimonialView";
}
with
#RequestMapping(URLs.TESTIMONIAL_VIEW)
and
String href= URLs.TESTIMONIAL_VIEW + "/" + testimonialName;
There isn't any better practice for this afaik. Most you can do is, as Ashley said, is to use constants. But as with any other client-server situation such as the Web, if you change the contract (the url in this case) you'll have to do so for both the client (i.e. the links) and the server (the controller mappings).
I would also mention that your controller can be more general, for example have a "Testimonials" controller and "view/{name}" as an action within that controller.
Hope this helps

Java/JSTL: is it a good idea to put all URLs in an enum?

I'm working on a web app with Java servlets and JSP pages with JSTL.
I'd like to find a way to:
1) Easily refactor URLs
2) For any url, easily discover exactly what pages/servlets reference it. This way when making changes it should be easier to know the potential impact elsewhere.
I'm considering using an enum to store URLs.
Is this a good idea? If so, what's the best way to reference it via JSTL? Is there an alternative way to achieve the same goal?
//example code
public enum SiteUrl {
HOME("/"),CART("/cart"),PROFILE("/my-profile");
private final String url;
private SiteUrl(String url){
this.url = url;
}
public String getUrl(){
return url;
}
}
No. You can define all this navigation-related stuff in the deployment descriptor file(s). Putting it into code is a retrograde step.
I prefer DB rather then enum. Reasons as below:
Not easy to maintain the enum class because other people need to
update it too.
If your application is not support hot-deploy, u need to restart app
when add a new url.
Normally, u need to handle request at first, like clean parameters
part, before direct.A DB interface can do this.

RESTful services - how to design a URL with many parameters

I've developed REST services, but now I realized that I'm doing something wrong.
For example, I have a service which retrieves information about a specific device. Each device has an address: sector.room.group.id.
The URI I did for this GET method was: (...)/services_devices/{sector}/{room}/{group}/{id} But now I realized that I should not have used the '/' to separate the device address, right?
How should I pass the address to this method? Using ';' ?
My GET method is:
#GET
#Path("{sector}/{room}/{group}/{id}")
#Produces("application/json")
public String getDeviceName(#PathParam("sector") int sector, #PathParam("room") int room, #PathParam("group") int group, #PathParam("id") int id) throws Exception
{
String name = null;
try {
name = new DevicesManager().getDeviceName(sector, room, group, id);
} catch (Exception e) {
e.printStackTrace();
}
return name;
}
There is a simple way of change this, to have a correct URI? I have this "error" in many methods.
If there is a hierarchy in your resources path variables are appropriate.
It seems in your case there is a hierarchy between devices and address, but first comes the address and after the deviceName. "deviceName" can be considered a one more hierarchy step.
The best way to reflect the above relations would be the following url:
(...)/sector/room/group/id/deviceName
You can then have another attribute of the device mapped like this:
(...)/sector/room/group/id/deviceOwner
The JAX-RS mapping would be:
#GET
#Path("{sector}/{room}/{group}/{id}/deviceName")
#Produces("application/json")
public String getDeviceName(#PathParam ...) {
//impl.
}
And yes, if the deviceName is the only relevant attribute of the resource, then you can leave out "deviceName" and your orignal mapping is correct.
If the resource at /sector/room/group/id has many attributes you should consider returning a composed object for the path:
#GET
#Path("{sector}/{room}/{group}/{id}")
#Produces("application/json")
public Device getDeviceName(#PathParam...) {
}
REST architectural style introduces HATEOAS, which means that client and server are loosely coupled. Simply the client is not aware of how the URLs look like and gets them from previous responses. (it's similar like surfing thru HTML pages). Of course there will be at least one URL, an entry point, that is known to the client. From this point of view, your need to have correct URIs is irrelevant. What's correct URI? The URI is correct when its form is aligned with RFC.
You are probably introducing URL patterns, that are not RESTful, because it implicates tight coupling between client and server (the client must be aware of URL patterns and have ability to construct URLs from them; fill up sector/room/ etc. in your case)
See also this post:
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
My advice is; don't waste your time on URL patterns, make URLs simple as is possible, flat hierarchy has also many benefits, and follow HATEOAS principle.

Alternatives to com.google.appengine.api.datastore.Text?

In a Google App Engine JPA Entity a java.lang.String is limited to 500 character, while a com.google.appengine.api.datastore.Text has an unlimited size (with the caveat that entityManager.persist doesn't work with entities bigger than 1 Mb - I believe, but can't find the reference about it).
However, if I use the Google specific Text type, I would tightly couple my application with Google App Engine. I was wondering if there is a more lightweight way to achieve the same result, such as through some standard annotation.
Maybe, annotating a String with a JSR-303 annotation. If the size is above 500, it would know to use the non-indexed Text type. Example: #Size(max = 3000)
Obvsiously I'm just dreaming, but maybe there is some standard way to avoid App Engine specific data types. Anybody knows?
UPDATE: found issue 10, Support #Lob JPA annotation in datanucleus-appengine
DataNucleus plugin for Google App Engine.
I'm guessing you might have thought of this already; but I'm posting this anyway since it adds a point not covered in your question. My solution here was to make it private, and then for my object definition I don't ever return a Text object. I admit this doesn't accomplish your goal of avoiding the App Engine specific data type; but it at least makes it so that you don't have to rewrite code outside of the one class which relies on the Text object should you decide to port your application off of app engine.
So, for example, assuming text is a blogPost variable...
public class BlogPost {
private Text post;
// ...
public String getPost() {
return post.getValue();
}
public void setPost(String val) {
this.post = new Text(val);
}
}
If that code feels a little sloppy it might be slightly (I don't know how the Text#getValue method works internally) more efficient to do this...
public class BlogPost {
private Text post;
private String postValue;
// ...
public String getPost() {
return postValue;
}
public void setPost(String val) {
this.post = new Text(val);
this.postValue = val;
}
}

Does Spring MVC provide any Java API for constructing web links?

Right now, my web.xml is configured in the way that Spring MVC will take over anything that has *.html suffix. I have a few controllers that generate the web links based on current user state.
For instance, I have the following code to determine what the "Next" button should point to:
if (nextSlide != null) {
nextLink = String.format("/%s/module/%d/slide/%d.html", studyName, moduleId, nextSlide.getKey());
}
else {
nextLink = String.format("/%s/module/all.html", studyName);
}
But, I don't like this approach because I'm hardcoding the ".html" to the links here. I could certainly create a factory that generates links with ".html" suffix to hide from all the controller code, but that still requires me to hardcode ".html" once in my Java code... not too DRY.
I'm basically hoping Spring MVC has some APIs that allow me to construct the links. If these APIs don't exist, do you hardcode the suffix in the Java code like what I do here?
There is not. Given what you currently have, you have three options. Two of these are your option, and dwb's option. The other is to create your own taglib.
It seems like you're doing some kind of wizard functionality (where screen 2 is dependent on a click from screen 1). If that's the case, I would look into Spring Webflow.
Another possibility is to perform an AJAX callout to some sort of decision method, or you could handle this all on the client side with JavaScript.
Also, FWIW, I don't think coding .html is breaking DRY, but I would be concerned about maintenance in case your servlet ever matched on something other than this suffix. You could most likely do something similar to the below example by just essentially returning a new ModelAndView or redirecting to one at least:
#RequestMapping("slide/{id}")
public String goToSlide(#PathParam("id") String id, ModelMap model) {
model.adAttribute("slide", slideService.findById(id));
return "slides/slide";
}
#RequestMapping("all")
public String getAllSlides() {
return "slides/all";
}
#RequestMapping(value="slideshow/{id}", method=RequestMethod.GET)
public String getSlideshow(#PathParam("id") String slideshowId, ModelMap model) {
model.attAttribute("slideshow", slideshowService.findById(slideshowId));
return "slides/slideshow";
}
#RequestMapping(value="slideshow", method=RequestMethod.POST)
public String postSlideshow(#QueryParam("slideId") String slideId) {
if(slideId != null) {
return "slide/" + slideId;
}
return "redirect:all";
}
It seems like building URLs should be handled in the view rather than the controller. Moving it to the view would eliminate the need to hard code anything in Java. You'd also be able to make use of Spring's URL tag. From the Spring API docs:
<spring:url value="/url/path/{variableName}">
<spring:param name="variableName" value="more than JSTL c:url" />
</spring:url>
// Results in: /currentApplicationContext/url/path/more%20than%20JSTL%20c%3Aurl

Categories

Resources