REST URI Design : Optional and multivalue information passing - java

I have one search widget where people search for car dealers by zip code. There are also some optional checkboxes to refine search in that widget.
Here is the URI for searching dealer by zip code.
http://localhost:8080/dealer/zip/10080
If user selects checboxes then the URI will be
http://localhost:8080/dealer/zip/10080servicetype=type1&servicetype=type2&servicetype=type3
I am using jersey. Here is java code.
#Path("/dealer")
#Produces(MediaType.APPLICATION_JSON)
public class DealerLocatorRS {
private DealerService dealerService=new DealerService();
#GET
#Path("/zip/{zip}")
public List<Dealer> getByZip(#PathParam("zip") String zip,
#QueryParam("servicetype") List<String> servicetype){
.. . ..
}
Is this right approach to pass optional and multiple values and . Can anybody help me to apply best practices?

I'm not sure that I'd map a search for dealers in a particular zip code to a resource; it doesn't feel quite right. Instead, I'd have a resource that lists all the dealers, with individual dealers being sub-resources of that. If it was possible to return a subset of the list of subresources restricted by properties (e.g., their zip code) then that would be a great way to implement a search, otherwise I'd have a separate search handler that returns a list of links to matching dealer resources.
#Path("/dealer")
public class Dealers {
#GET
public List<Dealer> getAll() { ... }
#GET
#Path("search/byZip")
public List<URI> getByZip(#QueryParam("zip") String zip, ...) { ... }
#Path("{dealerId:[^/]+}")
public Dealer getDealer(#PathParam("dealerId") String id) { ... }
}

If you are serious about understanding and applying REST, I'd recommend reading the REST paper, if you haven't done so yet.
According to the architecture proposed in that paper, Each URL maps to a resource.
A resource could be something extrinsic and tangible, like a car dealership. Or it could be something "virtual" like a "region", or even a zipcode that might contain dealerships.
As to how you parameterize queries, think about what resource you want to use to satisfy or expose the queries. Why would you treat "zipcode" as a variable parameter, any differently than, say your "servicetype"? Are they not both qualifiers to select a subset of dealerships? Think about why you are making them different - there may be a good reason.
For example, you could do:
http://server/dealer/zip/10070
list all dealers in 10070
http://server/dealer/service/transmissions
list all dealers that do transmission work
http://server/dealer/service/transmissions/zip/10070
list all dealers that do transmission work in zip 10070
http://server/dealer/zip/10070/service/transmissions
list all dealers in zip 10070 that do transmission work
http://server/dealer/service/transmissions/service/lighttrucks
list all dealers that do transmission work and do light truck service
Think about the mapping of URLs to resources. It may be that two distinct URLs map to the same "result". you need to decide whether that's appropriate for you.
It's also perfectly fine to retrieve a resource and then do queries on it on the client side. Not all work need be done by the server. You could search through the results obtained by http://server/dealer/zip/10070 on the client side, to find the ones that supply the desired services. This may or may not be a performance win, depending on the size of the data transmitted and the frequency and variety of queries.
Supposing an overall result set of 10 (say, ten dealers within a zipcode), a Javascript foreach loop searching for a dealer that offers service X is going to be faster than an additional AJAX call asking the server to do that query on behalf of the client.

This is ok, unless your URL becomes too long (although URL length is not limited by any spec, some browsers and intermediaries limit it, so the best practices to keep it under 1K)
If it becomes too long, you may use POST instead of GET.
P.S. You have bug in your code, it should be #QueryParam("servicetype") List<String> servicetype) to match the example URI.

Related

javax pathparam is being ignored [duplicate]

I am not asking the question that is already asked here:
What is the difference between #PathParam and #QueryParam
This is a "best practices" or convention question.
When would you use #PathParam vs #QueryParam.
What I can think of that the decision might be using the two to differentiate the information pattern. Let me illustrate below my LTPO - less than perfect observation.
PathParam use could be reserved for information category, which would fall nicely into a branch of an information tree. PathParam could be used to drill down to entity class hierarchy.
Whereas, QueryParam could be reserved for specifying attributes to locate the instance of a class.
For example,
/Vehicle/Car?registration=123
/House/Colonial?region=newengland
/category?instance
#GET
#Path("/employee/{dept}")
Patient getEmployee(#PathParam("dept")Long dept, #QueryParam("id")Long id) ;
vs /category/instance
#GET
#Path("/employee/{dept}/{id}")
Patient getEmployee(#PathParam("dept")Long dept, #PathParam("id")Long id) ;
vs ?category+instance
#GET
#Path("/employee")
Patient getEmployee(#QueryParam("dept")Long dept, #QueryParam("id")Long id) ;
I don't think there is a standard convention of doing it. Is there? However, I would like to hear of how people use PathParam vs QueryParam to differentiate their information like I exemplified above. I would also love to hear the reason behind the practice.
REST may not be a standard as such, but reading up on general REST documentation and blog posts should give you some guidelines for a good way to structure API URLs. Most rest APIs tend to only have resource names and resource IDs in the path. Such as:
/departments/{dept}/employees/{id}
Some REST APIs use query strings for filtering, pagination and sorting, but Since REST isn't a strict standard I'd recommend checking some REST APIs out there such as github and stackoverflow and see what could work well for your use case.
I'd recommend putting any required parameters in the path, and any optional parameters should certainly be query string parameters. Putting optional parameters in the path will end up getting really messy when trying to write URL handlers that match different combinations.
This is what I do.
If there is a scenario to retrieve a record based on id, for example you need to get the details of the employee whose id is 15, then you can have resource with #PathParam.
GET /employee/{id}
If there is a scenario where you need to get the details of all employees but only 10 at a time, you may use query param
GET /employee?start=1&size=10
This says that starting employee id 1 get ten records.
To summarize, use #PathParam for retrieval based on id. User #QueryParam for filter or if you have any fixed list of options that user can pass.
I think that if the parameter identifies a specific entity you should use a path variable. For example, to get all the posts on my blog I request
GET: myserver.com/myblog/posts
to get the post with id = 123, I would request
GET: myserver.com/myblog/posts/123
but to filter my list of posts, and get all posts since Jan 1, 2013, I would request
GET: myserver.com/myblog/posts?since=2013-01-01
In the first example "posts" identifies a specific entity (the entire collection of blog posts). In the second example, "123" also represents a specific entity (a single blog post). But in the last example, the parameter "since=2013-01-01" is a request to filter the posts collection not a specific entity. Pagination and ordering would be another good example, i.e.
GET: myserver.com/myblog/posts?page=2&order=backward
Hope that helps. :-)
I personally used the approach of "if it makes sense for the user to bookmark a URLwhich includes these parameters then use PathParam".
For instance, if the URL for a user profile includes some profile id parameter, since this can be bookmarked by the user and/or emailed around, I would include that profile id as a path parameter. Also, another considerent to this is that the page denoted by the URL which includes the path param doesn't change -- the user will set up his/her profile, save it, and then unlikely to change that much from there on; this means webcrawlers/search engines/browsers/etc can cache this page nicely based on the path.
If a parameter passed in the URL is likely to change the page layout/content then I'd use that as a queryparam. For instance, if the profile URL supports a parameter which specifies whether to show the user email or not, I would consider that to be a query param. (I know, arguably, you could say that the &noemail=1 or whatever parameter it is can be used as a path param and generates 2 separate pages -- one with the email on it, one without it -- but logically that's not the case: it is still the same page with or without certain attributes shown.
Hope this helps -- I appreciate the explanation might be a bit fuzzy :)
You can use query parameters for filtering and path parameters for grouping. The following link has good info on this When to use pathParams or QueryParams
Before talking about QueryParam & PathParam. Let's first understand the URL & its components. URL consists of endpoint + resource + queryParam/ PathParam.
For Example,
URL: https://app.orderservice.com/order?order=12345678
or
URL: https://app.orderservice.com/orders/12345678
where
endpoint: https://app.orderservice.com
resource: orders
queryParam: order=12345678
PathParam: 12345678
#QueryParam:
QueryParam is used when the requirement is to filter the request based on certain criteria/criterias. The criteria is specified with ? after the resource in URL. Multiple filter criterias can be specified in the queryParam by using & symbol.
For Example:
https://app.orderservice.com/orders?order=12345678 & customername=X
#PathParam:
PathParam is used when the requirement is to select the particular order based on guid/id. PathParam is the part of the resource in URL.
For Example:
https://app.orderservice.com/orders/12345678
It's a very interesting question.
You can use both of them, there's not any strict rule about this subject, but using URI path variables has some advantages:
Cache:
Most of the web cache services on the internet don't cache GET request when they contains query parameters.
They do that because there are a lot of RPC systems using GET requests to change data in the server (fail!! Get must be a safe method)
But if you use path variables, all of this services can cache your GET requests.
Hierarchy:
The path variables can represent hierarchy:
/City/Street/Place
It gives the user more information about the structure of the data.
But if your data doesn't have any hierarchy relation you can still use Path variables, using comma or semi-colon:
/City/longitude,latitude
As a rule, use comma when the ordering of the parameters matter, use semi-colon when the ordering doesn't matter:
/IconGenerator/red;blue;green
Apart of those reasons, there are some cases when it's very common to use query string variables:
When you need the browser to automatically put HTML form variables into the URI
When you are dealing with algorithm. For example the google engine use query strings:
http:// www.google.com/search?q=rest
To sum up, there's not any strong reason to use one of this methods but whenever you can, use URI variables.
From Wikipedia: Uniform Resource Locator
A path, which contains data, usually organized in hierarchical form, that appears as a sequence of segments separated by slashes.
An optional query, separated from the preceding part by a question mark (?), containing a query string of non-hierarchical data.
— According with the conceptual design of the URL, we might implement a PathParam for hierarchical data/directives/locator components, or implement a QueryParam when the data are not hierarchical. This makes sense because paths are naturally ordered, whereas queries contain variables which may be ordered arbitrarily (unordered variable/value pairs).
A previous commenter wrote,
I think that if the parameter identifies a specific entity you should use a path variable.
Another wrote,
Use #PathParam for retrieval based on id. User #QueryParam for filter or if you have any fixed list of options that user can pass.
Another,
I'd recommend putting any required parameters in the path, and any optional parameters should certainly be query string parameters.
— However, one might implement a flexible, non-hierarchical system for identifying specific entities! One might have multiple unique indexes on an SQL table, and allow entities to be identified using any combination of fields that comprise a unique index! Different combinations (perhaps also ordered differently), might be used for links from various related entities (referrers). In this case, we might be dealing with non-hierarchical data, used to identify individual entities — or in other cases, might only specify certain variables/fields — certain components of unique indexes — and retrieve a list/set of records. In such cases, it might be easier, more logical and reasonable to implement the URLs as QueryParams!
Could a long hexadecimal string dilute/diminish the value of keywords in the rest of the path? It might be worth considering the potential SEO implications of placing variables/values in the path, or in the query, and the human-interface implications of whether we want users to be able to traverse/explore the hierarchy of URLs by editing the contents of the address bar. My 404 Not Found page uses SSI variables to automatically redirect broken URLs to their parent! Search robots might also traverse the path hierarchy.
On the other hand, personally, when I share URLs on social media, I manually strip out any private unique identifiers — typically by truncating the query from the URL, leaving only the path: in this case, there is some utility in placing unique identifiers in the path rather than in the query. Whether we want to facilitate the use of path components as a crude user-interface, perhaps depends on whether the data/components are human-readable or not. The question of human-readability relates somewhat to the question of hierarchy: often, data that may be expressed as human-readable keywords are also hierarchical; while hierarchical data may often be expressed as human-readable keywords. (Search engines themselves might be defined as augmenting the use of URLs as a user-interface.) Hierarchies of keywords or directives might not be strictly ordered, but they are usually close enough that we can cover alternative cases in the path, and label one option as the "canonical" case.
There are fundamentally several kinds of questions we might answer with the URL for each request:
What kind of record/ thing are we requesting/ serving?
Which one(s) are we interested in?
How do we want to present the information/ records?
Q1 is almost certainly best covered by the path, or by PathParams.
Q3 (which is probably controlled via a set of arbitrarily ordered optional parameters and default values); is almost certainly best covered by QueryParams.
Q2: It depends…
PATH PARAMETER -
Path Parameter is a variable in URL path that helps to point some specific resource.
Example - https://sitename.com/questions/115
Here, if 115 is a path parameter it can be changed with other valid number to fetch/point to some other resource on the same application.
QUERY PARAMETER -
Query Parameters are variables in URL path that filter some particular resources from the list.
Example - https://sitename.com/questions/115?qp1=val1&qp2=val2&qp3=val3
Here qp1, qp2 and qp3 are Query Variables with their values as val1, val2 and val3. These can be used to apply as filters while fetching/saving our data. Query variables are always appended in URL after a question Mark(?).
As theon noted, REST is not a standard. However, if you are looking to implement a standards based URI convention, you might consider the oData URI convention. Ver 4 has been approved as an OASIS standard and libraries exists for oData for various languages including Java via Apache Olingo. Don't let the fact that it's a spawn from Microsoft put you off since it's gained support from other industry player's as well, which include Red Hat, Citrix, IBM, Blackberry, Drupal, Netflix Facebook and SAP
More adopters are listed here
You can support both query parameters and path parameters, e.g., in the case of aggregation of resources -- when the collection of sub-resources makes sense on its own.
/departments/{id}/employees
/employees?dept=id
Query parameters can support hierarchical and non-hierarchical subsetting; path parameters are hierarchical only.
Resources can exhibit multiple hierarchies. Support short paths if you will be querying broad sub-collections that cross hierarchical boundaries.
/inventory?make=toyota&model=corolla
/inventory?year=2014
Use query parameters to combine orthogonal hierarchies.
/inventory/makes/toyota/models/corolla?year=2014
/inventory/years/2014?make=toyota&model=corolla
/inventory?make=toyota&model=corolla&year=2014
Use only path parameters in the case of composition -- when a resource doesn't make sense divorced from its parent, and the global collection of all children is not a useful resource in itself.
/words/{id}/definitions
/definitions?word=id // not useful
I prefer following :
#PathParam
When it's required parameters such as ID, productNo
GET /user/details/{ID}
GET /products/{company}/{productNo}
#QueryParam
When you need to pass optional parameters such as filters, online state and They can be null
GET /user/list?country=USA&status=online
GET /products/list?sort=ASC
When Used both
GET /products/{company}/list?sort=ASC
The reason is actually very simple. When using a query parameter you can take in characters such as "/" and your client does not need to html encode them. There are other reasons but that is a simple example. As for when to use a path variable. I would say whenever you are dealing with ids or if the path variable is a direction for a query.
I am giving one exapmle to undersand when do we use #Queryparam and #pathparam
For example I am taking one resouce is carResource class
If you want to make the inputs of your resouce method manadatory then use the param type as #pathaparam, if the inputs of your resource method should be optional then keep that param type as #QueryParam param
#Path("/car")
class CarResource
{
#Get
#produces("text/plain")
#Path("/search/{carmodel}")
public String getCarSearch(#PathParam("carmodel")String model,#QueryParam("carcolor")String color) {
//logic for getting cars based on carmodel and color
-----
return cars
}
}
For this resouce pass the request
req uri ://address:2020/carWeb/car/search/swift?carcolor=red
If you give req like this the resouce will gives the based car model and color
req uri://address:2020/carWeb/car/search/swift
If you give req like this the resoce method will display only swift model based car
req://address:2020/carWeb/car/search?carcolor=red
If you give like this we will get ResourceNotFound exception because in the car resouce class I declared carmodel as #pathPram that is you must and should give the carmodel as reQ uri otherwise it will not pass the req to resouce but if you don't pass the color also it will pass the req to resource why because the color is #quetyParam it is optional in req.
#QueryParam can be conveniently used with the Default Value annotation so that you can avoid a null pointer exception if no query parameter is passed.
When you want to parse query parameters from a GET request, you can simply define respective parameter to the method that will handle the GET request and annotate them with #QueryParam annotation
#PathParam extracts the URI values and matches to #Path. And hence gets the input parameter.
2.1 #PathParam can be more than one and is set to methods arguments
#Path("/rest")
public class Abc {
#GET
#Path("/msg/{p0}/{p1}")
#Produces("text/plain")
public String add(#PathParam("p0") Integer param1, #PathParam("p1") Integer param2 )
{
return String.valueOf(param1+param2);
}
}
In the above example,
http://localhost:8080/Restr/rest/msg/{p0}/{p1},
p0 matches param1 and p1 matches param2. So for the URI
http://localhost:8080/Restr/rest/msg/4/6,
we get the result 10.
In REST Service, JAX-RS provides #QueryParam and #FormParam both for accepting data from HTTP request. An HTTP form can be submitted by different methods like GET and POST.
#QueryParam : Accepts GET request and reads data from query string.
#FormParam: Accepts POST request and fetches data from HTML form or any request of the media
In nutshell,
#Pathparam works for value passing through both Resources and Query String
/user/1
/user?id=1
#Queryparam works for value passing only Query String
/user?id=1
For resource names and IDs, I use #PathParams. For optional variables, I use #QueryParams
As per my understanding:
Use #PathParam - when it is a mandatory item such as an Id
GET /balloon/{id}
Use #QueryParam - when you have the exact resource but need to filter that on some optional traits such as color, size, etc.
GET /balloon/123?color=red&size=large

Pass list of objects to GET rest service

I would like to pass a list of objects to a java rest service. For example, list of cycles.
class Cycle {
private String id;
private LocalDate date;
}
#GetMapping("results")
public Result results(List<Cycle> cycles)
Or have a CyclesWrapper class that contains the list. Instead of passing a List cycleDates and a List cycleIds.
How would I pass the parameters to the rest service using say POSTMAN or curl?
So, for passing in a List<String> says cycleIds, the request would be:
http://localhost:8080/application/results?cycleIds=xx,yy
For passing in a Cycle says cycle, the request would be:
http://localhost:8080/application/results?date=2020-10-17&id=xx
Thanks
As it currently stands, your endpoint would interpret cycles as a query parameter, meaning that it would expect the following kind of request:
GET /results?cycles=...
With a list of complex objects, this is not the standard approach. You could possibly pass the objects as /results?cycle1Id=abc&cycle1Date=22-10&cycle2Id=def&cycle2Date=10-10&..., but this would be extremely cumbersome, error-prone, and would require custom mapping on your end to make it work. Additionally, as far as I am aware, there is no standard for sending query array parameters.
Note also, in case you might have misconstrued: you cannot send a request body on a GET request - while the standard does not explicitly disallow this, almost every server's handling of GET does not accept (or just flatly ignores) a request body.
Instead, what you could do, is either:
Change the endpoint to a POST endpoint, passing the list of cycles (i.e. filters) as standard #RequestBody JSON. This would look as follows:
#PostMapping("results")
public Result results(#RequestBody List<Cycle> cycles)
Now your request would expect:
POST /results
{
[
{"abc", "22-10"},
{"def", "10-10"}
]
}
Since POST is allowed to pretty much do anything, it could also return a filtered response on this endpoint. This would however, not be very RESTful.
Change your GET to accept two lists of of simple (i.e. non-nested) objects, e.g. String and LocalDate.
#GetMapping("results")
public Result results(#RequestParam List<String> ids, #RequestParam List<LocalDate> dates)
Which would then expect a request as follows:
GET /results?ids=abc,def&dates=22-10,10-10
as a comma-separated list. This is more in tune with RESTful endpoints, although it's also kind of cumbersome.
In the end, it seems like your endpoint is trying to do two things at once: filter on id and date. Since I am not sure what kind of logical work represents a cycle, perhaps these should be split up into two different endpoints, e.g.:
===>
GET /results?dateFrom=22-10&dateUntil=23-10
<===
[abc, def]
==>
GET /results/abc?dateFrom=22-10&dateUntil=23-10
<==
abc detailed view
Where the /abc represents a singular object. Whether this represents a result or a cycle in your specific case, I cannot say. You'd have to evaluate that for yourself.

Sorting rest get request results by field passed as a parameter

I am currently working on a Rest API, in a get method which suppose to return an Array of objects in json format I now have the requirement to sort the result by a field passed as a parameter to the method. Consider for example the object to be
public class ExampleType {
int firstField ;
String secondField ;
}
Now according to the requirements the Rest API user should be able to pass as a parameter among other things either "firstField" or "secondField" and I should be sorting the array containing the result objects using this field.
Apparently my model is not so simplistic as the example, I do have more than 15 fields which could potentially be the one that I need to sort by, so an else if statement is not a choice at this point. My question is does anybody had a similar requirement for a rest api and if so how did you tackle it ? Or any recommendation on what could potentially by an elegant solution to my problem would be greatly appreciated.
You should create a Comparator and then use this to sort your data.
The comparators could be stored in a static map to avoid a switch/case if/else:
map.put("fieldName", Comparator.comparing(ExampleType::getFirstField));
You can combine two or more comparators using the thenComparing method.
The only other option is to create the appropriate comparators using reflection.
Note: requirements of API consumers often are not requirements that should be implemented in the API itself. You may also consider that sorting output is in fact a display problem and not something that an API needs to be concerned with.
It depends on the situation though, if data needs to be paginated then you may have no option other than to sort at the API level.

DTOs with different granularity

I'm on a project that uses the latest Spring+Hibernate for persistence and for implementing a REST API.
The different tables in the database contain lots of records which are in turn pretty big as well. So, I've created a lot of DAOs to retrieve different levels of detail and their accompanying DTOs.
For example, if I have some Employee table in the database that contains tons of information about each employee. And if I know that any client using my application would benefit greatly from retrieving different levels of detail of an Employee entity (instead of being bombarded by the entire entity every time), what I've been doing so far is something like this:
class EmployeeL1DetailsDto
{
String id;
String firstName;
String lastName;
}
class EmployeeL2DetailsDto extends EmployeeL1DetailsDto
{
Position position;
Department department;
PhoneNumber workPhoneNumber;
Address workAddress;
}
class EmployeeL3DetailsDto extends EmployeeL2DetailsDto
{
int yearsOfService;
PhoneNumber homePhoneNumber;
Address homeAddress;
BidDecimal salary;
}
And So on...
Here you see that I've divided the Employee information into different levels of detail.
The accompanying DAO would look something like this:
class EmployeeDao
{
...
public List<EmployeeL1DetailsDto> getEmployeeL1Detail()
{
...
// uses a criteria-select query to retrieve only L1 columns
return list;
}
public List<EmployeeL2DetailsDto> getEmployeeL2Detail()
{
...
// uses a criteria-select query to retrieve only L1+L2 columns
return list;
}
public List<EmployeeL3DetailsDto> getEmployeeL3Detail()
{
...
// uses a criteria-select query to retrieve only L1+L2+L3 columns
return list;
}
.
.
.
// And so on
}
I've been using hibernate's aliasToBean() to auto-map the retrieved Entities into the DTOs. Still, I feel the amount of boiler-plate in the process as a whole (all the DTOs, DAO methods, URL parameters for the level of detail wanted, etc.) are a bit worrying and make me think there might be a cleaner approach to this.
So, my question is: Is there a better pattern to follow to retrieve different levels of detail from a persisted entity?
I'm pretty new to Spring and Hibernate, so feel free to point anything that is considered basic knowledge that you think I'm not aware of.
Thanks!
I would go with as little different queries as possible. I would rather make associations lazy in my mappings, and then let them be initialized on demand with appropriate Hibernate fetch strategies.
I think that there is nothing wrong in having multiple different DTO classes per one business model entity, and that they often make the code more readable and maintainable.
However, if the number of DTO classes tends to explode, then I would make a balance between readability (maintainability) and performance.
For example, if a DTO field is not used in a context, I would leave it as null or fill it in anyway if that is really not expensive. Then if it is null, you could instruct your object marshaller to exclude null fields when producing REST service response (JSON, XML, etc) if it really bothers the service consumer. Or, if you are filling it in, then it's always welcome later when you add new features in the application and it starts being used in a context.
You will have to define in one way or another the different granularity versions. You can try to have subobjects that are not loaded/set to null (as recommended in other answers), but it can easily get quite awkward, since you will start to structure your data by security concerns and not by domain model.
So doing it with individual classes is after all not such a bad approach.
You might want to have it more dynamic (maybe because you want to extend even your data model on db side with more data).
If that's the case you might want to move the definition out from code to some configurations (could even be dynamic at runtime). This will of course require a dynamic data model also on Java side, like using a hashmap (see here on how to do that). You gain thereby a dynamic data model, but loose the type safety (at least to a certain extend). In other languages that probably would feel natural but in Java it's less common.
It would now be up to your HQL to define on how you want to populate your object.
The path you want to take depends now a lot on the context, how your object will get used
Another approach is to use only domain objects at Dao level, and define the needed subsets of information as DTO for each usage. Then convert the Employee entity to each DTO's using the Generic DTO converter, as I have used lately in my professional Spring activities. MIT-licenced module is available at Maven repository artifact dtoconverter .
and further info and user guidance at author's Wiki:
http://ratamaa.fi/trac/dtoconverter
Quickest idea you get from the example page there:
Happy hunting...
Blaze-Persistence Entity Views have been created for exactly such a use case. You define the DTO structure as interface or abstract class and have mappings to your entity's attributes. When querying, you just pass in the class and the library will take care of generating an optimized query for the projection.
Here a quick example
#EntityView(Cat.class)
public interface CatView {
#IdMapping("id")
Integer getId();
String getName();
}
CatView is the DTO definition and here comes the querying part
CriteriaBuilder<Cat> cb = criteriaBuilderFactory.create(entityManager, Cat.class);
cb.from(Cat.class, "theCat")
.where("father").isNotNull()
.where("mother").isNotNull();
EntityViewSetting<CatView, CriteriaBuilder<CatView>> setting = EntityViewSetting.create(CatView.class);
List<CatView> list = entityViewManager
.applySetting(setting, cb)
.getResultList();
Note that the essential part is that the EntityViewSetting has the CatView type which is applied onto an existing query. The generated JPQL/HQL is optimized for the CatView i.e. it only selects(and joins!) what it really needs.
SELECT
theCat.id,
theCat.name
FROM
Cat theCat
WHERE theCat.father IS NOT NULL
AND theCat.mother IS NOT NULL

Sortable HTML table in Java

I want to add sorting to a HTML table populated by Hibernate. The actual sorting has to be done by a database. To feed "Order by" condition to the database Java has to match passed sort parameters to a column in a query. I'm unsure how to implement this matching.
I could pass something like "Employee.salary" but then this condition need to be checked like all parameters passed from client. This check would require getting column name from Hibernate annotations, and this is not easy I guess. Also, the column can be query-specific and not corresponding to a table field.
Another way is to use hardcoded values in a presentation layer. But this will tie presentation layer with a persistence layer, which is also not good I think.
How do you deal with server-side sorting in web applications?
You have to create some kind of an intermediate layer that maps the column names between the view and the tables. This way you can send extra parameters to your query in an encapsulated form, and in your server side code you can use them according to your actual query.
For sorting do sth like this:
public class ColumnMapping {
String tableColName;
String dbColName;
//getters, setters, ctors and anything else required
}
List<ColumnMapping > orderColumns = new ArrayList<ColumnMapping >();
orderColumns.add(new ColumnMapping("foo", "bar"));
//... server side
StringBuilder queryString = new StringBuilder("select * from books ");
if(orderingApplicable) {
queryString.appendd("order by ");
queryString.append(implode(orderColumns, ", "));
}
Where implode is a theoretical function gluing the list elements with commas into a string.
Remarks:
You can easily pre-populate the view-db mapping on startup if immutable.
The same can be done for group by.
This is just a stub, but extensible to include aggregate functions or whatever you need
If I have an Employee entity, then I want an EmployeeRepository that lets me findEmployeesBySalary(SortType sortType, int skip, int limit)
From the web service side, I want a URI like
foo.com/employees?by=salary&skip=10&limit=50
which returns something like (as a AJAX XHR call)
<employees>
<employee uri="/employee/1" />
<employee uri="/employee/2" />
<employee uri="/employee/3" />
</employees>
or the full-blown HTML page rendered appropriate.
This conveniently allows caching of employees on the client side (which the cache size being flexible) and at the HTTP level.
Note that, column names? Irrelevant. You would have a HiberateEmployeeRepository that implements the EmployeeRepository interface as needed. Express this stuff as methods, and use complex parameters if you need to.
You could even have two separate methods if you want, rather than an enum, findHighestPaidEmployees and findLowestPaidEmployees - foo.com/employees?salary=lowest&skip=10&take=30 mind you, that's a horribly depressing URI.
You could sort data at the client side, with help various js tools. It will be minimize requests to database

Categories

Resources