<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-25299220</id><updated>2009-10-27T07:09:54.540+01:00</updated><title type='text'>Flo Ledermann</title><subtitle type='html'>&lt;a href="http://floledermann.blogspot.com/search/label/tech"&gt; code
&lt;/a&gt; - &lt;a href="http://floledermann.blogspot.com/search/label/ontology"&gt;
ontology
&lt;/a&gt; - &lt;a href="http://floledermann.blogspot.com/search/label/politics"&gt;
politics
&lt;/a&gt;
&lt;br&gt; &lt;a href="http://floledermann.blogspot.com/search/label/english"&gt;
english&lt;/a&gt; - &lt;a href="http://floledermann.blogspot.com/search/label/deutsch"&gt;
deutsch
&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://floledermann.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/-/code'/><link rel='alternate' type='text/html' href='http://floledermann.blogspot.com/search/label/code'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Flo</name><uri>http://www.blogger.com/profile/13456675247042447579</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-25299220.post-9075022455886942360</id><published>2007-12-10T16:35:00.000+01:00</published><updated>2007-12-19T20:48:06.663+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>Towards the perfect URL scheme for web applications. Part 1: Requirements</title><content type='html'>[This is part one of a four-part article. I will add links to the other parts here as they become available.]&lt;br /&gt;&lt;br /&gt;I am currently working on a prototype for a small, new, top-secret web application (don't worry, I will let you know as soon as there is something online to show). When I sat down to start coding, the first thing I had to decide on was what the URLs inside the application should look like and how the URL space should be structured. I always had the impression that the question of how to design URLs for web applications has been largely neglected by the web developer community as I never read anything about a structured approach towards the problem — although it is a very visible feature and often the first usability test a site has to pass. So many apps and websites out there come with unreadable, unhackable URLs and/or, even worse, do not produce meaningful filenames when you try "save as..." on a page or downloadable file. I wanted to really get this right in the first place, so I started with writing down the things that annoy me regarding how URLs are constructed elsewhere, added a few "nice to have" features and lessons learned from my own previous experiences and compiled a requirements list that my scheme&lt;sup&gt;(1)&lt;/sup&gt; should meet.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Requirements for a perfect URL scheme&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When I talk about "modern web applications" here I have a rough concept of the state of the art in mind (buzzword alert!): AJAX interface with a fallback to server-driven interactivity, REST APIs&lt;sup&gt;(2)&lt;/sup&gt;, widgetizable applications and an object-oriented data model. Other websites may have different requirements, but most of what I say here will apply to a broad range of applications.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. URLs should be human readable, rememberable and robust for voice communication (e.g. phone)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the most important requirements for URLs is that they should make sense to a human. Machine-generated identifiers, deep folder hierarchies, special characters, strange extensions or query parameters are examples for URL parts that humans cannot easily parse or remember. More often than you think URLs are communicated by voice communication, over the phone or in the radio, therefore they should unambiguously serialze and deserialize from spoken language (which, by the way, is also a strong case for non-case sensitive or all-lowercase URLs).&lt;br /&gt;&lt;br /&gt;Obviously this requirement cannot be solved by a specification or scheme alone, but also lies in the application's responsibility. For example, if you have a document with the name 'qa4@@67g$O', the best scheme will not help you to provide a human readable URL.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. URLs should be short&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While this requirement is slightly related to the previous one, it is not the same. A longer URL may be much easier to remember, as you can easily try by using one of these tinyurl.com generated URLs. Still, partly for the reason of transmitting and displaying on devices with limited capabilities (think text messages), the URLs of our system should be naturally short with no superfluous namespaces, extensions or query parameters.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. The scheme should produce meaningful filenames &amp;amp; extensions for every page and file served&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is one of my top annoyances on the web, as most web applications fail to fulfill this requirement. Even with document servers that are supposed to provide files for download (e.g. PDFs), I frequently encounter missing extensions, not to speak of meaningful and unambiguous filenames. Whenever we serve a non-temporary page or document for viewing&lt;br /&gt;it should be possible for the user to save that page to her local machine, getting a meaningful filename with the correct filename extension.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4. The scheme should make use of established specifications and conventions — filename extensions ('.'), hierarchy ('/'), queries ('?'), fragments ('#')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Obviously I do not want to reinvent URLs, but build on top of established standards and conventions. The problem is that these standards have emerged in a time before XML, Javascript and AJAX, and so we have to find an interpretation of the concepts offered to us that match the requirements of modern web applications.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5. The scheme should use as few reserved characters as possible, leaving most of the allowed character set for the application&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I want to avoid introducing reserved characters in addition to the ones mentioned above  - partly because it would be a nonstandard extension to what we already have, partly because human readability would suffer by introducing additional non-letter characters.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;6. URLs should be "hackable"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Closely related to human parseability requested in requirement 1, "hackability" means that parts of the URL could be removed or added by users, leading to deterministic, meaningful results. Some examples of this would be: removing everything after the last '/' should give you an overview of the content one level up a hierarchy, removing or changing extensions should change the content type served, adding parts of an URL seen elsewhere on the site should result in similar behavior on any other resource etc.. Note that a system with "hackable" URLs should also protect the user from accidentally modifying or deleting resources this way, so that users can safely play around with the URL scheme without causing damage.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;7. URLs should be able to address resources AND actions to be performed on these resources&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is the major new requirement I see with modern web applications. When HTTP was designed, URLs were meant as a way to access resources, in most cases static files. The operations to be performed on these resources were pushed into the HTTP protocol in form of the GET, PUT, POST, ... methods. In modern web applications it turned out that a predefined set of methods cannot cover all the different requirements that may emerge. We therefore need a way to express actions to be performed on resources within the URL, since no other method is provided by the HTTP protocol.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;8. Resources or results of an action should be presentable in different formats (HTML, XML, JSON, plain text, ...), providing correct file name extensions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As static pages play a less important role in modern web applications and standards for the exchange of various data flavours emerge, it is important to be able to present a resource (e.g. an article) in different formats (e.g. HTML, Plain Text and RSS). New standards are emerging all the time and may become relevant in the future, so the pool of formats to choose from should be expandable in the future to support yet unanticipated usage of the data.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;9. The scheme should support content to be served in a format determined by the preferences of the client application&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In addition to the explicit choice of format through the URL scheme discussed in the last item, the mechanism of implicit content format selection offered by HTTP through the "Accept" header&lt;sup&gt;(3)&lt;/sup&gt; should be supported. The Accept header allows the client to send a list of supported content types along with each request, allowing the server software to select a content type best suited for the task.&lt;br /&gt;&lt;br /&gt;This way our system can send different responses to a mobile phone and a full-fledged web browser, although both are using the same URL to access the content.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;10. It should be possible to mix static files and generated content&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Although static files play a less important role in modern web applications, it is obvious that every web application will need to serve static files form the file system to the client. While in production environments this is often solved by a dedicated subdomain (e.g. static.foo.com), it should still be possible to serve static files and generated content from a single server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;11. A single resource should have a single (normalized) URL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Flexible URL schemes often provide multiple paths to a single resource, leading to problems in unambiguously identifying resources. Search engines, for example, may not be able to conclude that two different URLs point to the same resource, usually leading to a reduced ranking for both pages. If multiple paths to a single resource are possible, an unambiguous normalization method (often called 'URL canonicalization') should be provided.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;12. Support the features of "standard" global filenames like robots.txt, sitemap.xml, favicon.ico&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Due to very unfortunate historical developments, some "standards" have emerged (none of them is actually a standard accepted by any official standardization authority) that rely on the presence of static files in the URL hierarchy of a server. Since these "standards" provide convenient or important functionality for many web applications, the URL scheme must either support these filenames by ensuring that no other resource can exist with an identical URL, or we need to find ways to support the features provided by these files through other means.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This concludes the requirements for a perfect URL scheme I have discovered and found important. In the next part (coming up soon!) I will discuss the constraints we face from the URL and HTTP specifications for designing our URLs. Part 3 will present the proposed URL scheme and Part 4 will discuss implementation issues. &lt;span style="font-style: italic;"&gt;Stay tuned!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Footnotes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1 - Let me state in advance that when I say "URL scheme" here, I do not mean to propose a new scheme outside the scope of what HTTP already supports. My intention is to find a way to structure the path component (everything that comes after the server name and port in the URL) in a way that reflects the needs of modern web applications.&lt;br /&gt;&lt;br /&gt;2 - I have to admit here I have never quite grasped what REST really is or why everyone is talking about it. As far as I understand, it is simply the concept of having a stateless API where every call is simply a HTTP request, and I have the vague idea that the URL scheme proposed here goes well along with it. If anyone has any further insigts, please enlighten me! (And yes, I have skimmed through the &lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/top.htm"&gt;dissertation&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;3 - The Accept header is discussed in detail in the &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"&gt;HTTP/1.1 specification (RFC2616), section 14&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Updates&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;2007-12-19: Added numbering to the individual requirements and added requirement 7 (Hackability)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25299220-9075022455886942360?l=floledermann.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floledermann.blogspot.com/feeds/9075022455886942360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25299220&amp;postID=9075022455886942360' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/9075022455886942360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/9075022455886942360'/><link rel='alternate' type='text/html' href='http://floledermann.blogspot.com/2007/12/towards-perfect-url-scheme-for-web.html' title='Towards the perfect URL scheme for web applications. Part 1: Requirements'/><author><name>Flo</name><uri>http://www.blogger.com/profile/13456675247042447579</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13692355615454251607'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25299220.post-3385948862610226734</id><published>2007-11-05T10:52:00.000+01:00</published><updated>2007-11-05T11:22:17.620+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gmaps'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='life'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>My talk at Web2Open this wednesday</title><content type='html'>I will be giving a talk at &lt;a href="http://web2open.eu/"&gt;Web2Open&lt;/a&gt; in Berlin (a free event attached to the O'Reilly &lt;a href="http://berlin.web2expo.com/"&gt;Web2.0 Expo&lt;/a&gt;) this Wednesday. The announced title and abstract of the talk are:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Advanced GPolyline usage - performance issues and interactivity&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;Due to different implementations on different browsers, complex and high resolution  Google polylines can lead to surprising  results up to non-responsive applications in some cases. I will present the - sometimes surprising - results of our performance  measurements, performance  improvement strategies and a comparison with an experimental alternative  implementation that can be also used for improved interactivity like  real-time editing or continuous panning along a line.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;But maybe you can best decide whether you are interested by looking at a &lt;a href="http://www.maptales.com/files/screencasts/02_routes.html"&gt;screencast&lt;/a&gt; of the implementation I did for &lt;a href="http://www.maptales.com/"&gt;maptales&lt;/a&gt;. In the talk, I will provide some details and hints how to implement the shown features for your own applications.&lt;br /&gt;&lt;br /&gt;Looking forward to see you at Web2Open!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25299220-3385948862610226734?l=floledermann.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floledermann.blogspot.com/feeds/3385948862610226734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25299220&amp;postID=3385948862610226734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/3385948862610226734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/3385948862610226734'/><link rel='alternate' type='text/html' href='http://floledermann.blogspot.com/2007/11/my-talk-at-web2open-this-wednesday.html' title='My talk at Web2Open this wednesday'/><author><name>Flo</name><uri>http://www.blogger.com/profile/13456675247042447579</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13692355615454251607'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-25299220.post-4017784879369009146</id><published>2007-10-28T12:34:00.001+01:00</published><updated>2008-02-17T14:31:32.088+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='english'/><title type='text'>Solving Hibernate Criteria's "Distinct Root Entity" limitation once and for all - including pagination</title><content type='html'>I have to start with a rant: The Hibernate Criteria API, which I learned to at least partially like over the last months working on &lt;a href="http://www.maptales.com/"&gt;Maptales&lt;/a&gt; server code, has a few limitations which repeatedly make me wonder whether Hibernate really has been the right choice for a DB abstraction layer from time to time. It's not so much the limitations themselves, but rather the total lack of documentation of these limitations in the official Hibernate docs and examples and the generally rather arrogant tone on the Hibernate mailing Lists and FAQs — if you get an answer at all, that is — that annoy me and I guess a lot of other Hibernate users. The examples provided — and therefore copied blindly into nearly every Tutorial or Book about Hibernate out there — always avoid to show these limitations because of the triviality of the scenarios they cover. The purpose of a proper documentation would — for me — be to document especially such limitations and border cases where an API fails and provide solutions for these cases.&lt;br /&gt;&lt;br /&gt;The problem is even amplified by the fact that googling for such limitiations rarely brings up a solution, since, as mentioned above, the hibernate documentation and inherited tutorials all do a good job in concealing the problems, and few coders out there seem to really use Hibernate in more sophisticated ways &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; publish their experiences. Which makes me wonder, because for these trivial cases too often good ol' SQL would have been perfectly sufficient — and advantageous to those lamer wannabee DB coders who would actually be forced to learn something about databases instead of replicating stupid Hibernate tutorial examples.&lt;br /&gt;&lt;br /&gt;&amp;lt;/rant&gt;&lt;br /&gt;&lt;br /&gt;OK now the specific limitation I want to talk about is: &lt;span style="font-style: italic;"&gt;Hibernate does not return distinct results for a query with outer join fetching enabled for a collection&lt;/span&gt;. At least that's what they call it in the &lt;a href="http://www.hibernate.org/117.html#A12"&gt;Hibernate advanced problems FAQ&lt;/a&gt;, failing to discuss this problem in deep and to give a general solution. Quote:&lt;br /&gt;&lt;blockquote&gt;&lt;em&gt;One day Hibernate might be smart enough to know that if you call &lt;tt&gt;setFirstResult()&lt;/tt&gt; or &lt;tt&gt;setMaxResults()&lt;/tt&gt; it should not use a join, but a second SQL &lt;tt&gt;SELECT&lt;/tt&gt;. Try it, your version of Hibernate might already be smart enough. If not, write two queries, one for limiting stuff, the other for eager fetching.&lt;/em&gt;&lt;/blockquote&gt;And here they are again cutting of a large part of the problem. First, I checked an my version of hibernate is not "smart" enough, and it &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-2480"&gt;does not look like&lt;/a&gt; it will get any smarter soon. Second, the approach proposed there did not work for me when querying on properties of objects inside a collection - the collection has to always be JOINed for the query to work, therefore always producing results useless for pagination after transforming to distinct root entities. Generally, my problem was harder in a number of ways than the ususal examples:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I am nearly always using criterias on collection members, therefore I cannot revert to SELECT fetching.&lt;/li&gt;&lt;li&gt;I always have to use pagination (setFirstResult() and setMaxResults()), because in a web application it is not nice to return thousands of results on one page.&lt;/li&gt;&lt;li&gt;I am using PostGreSQL which adds a few oddities above it all (see below)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;After digging through a lot of useless to semi-enlightening blog posts (thanks to Rick Hightower for providing &lt;a href="http://www.jroller.com/RickHigh/entry/hibernate_query_getting_rid_of"&gt;two thirds of the solution&lt;/a&gt;) I could finally come up with the ultimate solution that works for me now:&lt;br /&gt;&lt;br /&gt;First you have to accept that you have to live with 2 queries instead of one. You simply cannot do pagination &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; restrictions on collection members in hibernate in a single criteria query. Once you have accepted that fact, you can go ahead and construct your base query.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public List queryCats(Date queryDate) throws Exception {&lt;br /&gt;Criteria criteria = getSession().createCriteria(Cat.class);&lt;br /&gt;criteria.setFirstResult(offset).setMaxResults(num);&lt;br /&gt;criteria.addOrder(Order.asc("age"));&lt;br /&gt;if (queryDate != null) {&lt;br /&gt;  Criteria subCrit = criteria.createCriteria("kittens", "kitten");&lt;br /&gt;  subCrit.add(Expression.ge("birthDate", queryDate));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;What you need to do then is to project the result to a collection of ids of the objects that match the query, eliminating duplicates. Here also the mentioned speciality of Postgres (at a &lt;a href="http://archives.postgresql.org/pgsql-sql/2007-02/msg00169.php"&gt;second look&lt;/a&gt; it seems to be a general limitation) comes in: you have to include fields that are used for ordering in the projection clause. The nice thing is we can do the projection on demand and only if collection memebers are actually queried — this comes in handy for programatically constructed queries which can use the simple, single query way if collection properties are not used in the query:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  if (queryDate != null) {&lt;br /&gt;  // project result to distinct ids,&lt;br /&gt;  // including columns used for sorting&lt;br /&gt;  criteria.setProjection(Projections.distinct(&lt;br /&gt;    Projections.projectionList()&lt;br /&gt;      .add(Projections.id())&lt;br /&gt;      .add(Projections.property("birthDate"))&lt;br /&gt;  ));&lt;br /&gt;  List list = criteria.list();&lt;br /&gt;&lt;br /&gt;  // unfortunately we have to copy the ids out of the&lt;br /&gt;  // resulting Object[] List&lt;br /&gt;  List&lt;long&gt; idlist = new ArrayList&amp;lt;long&amp;gt;();&lt;br /&gt;&lt;br /&gt;  for (Iterator iditer = list.iterator(); iditer.hasNext();) {&lt;br /&gt;    Object[] record = (Object[]) iditer.next();&lt;br /&gt;    idlist.add((Long)record[0]);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // another Hibernate stupidity: empty Lists cause&lt;br /&gt;  // Expression.in to throw an error&lt;br /&gt;  if (idlist.size() &gt; 0) {&lt;br /&gt;    criteria = getSession().createCriteria(Cat.class);&lt;br /&gt;    criteria.add(Expression.in("id", idlist));&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    return new ArrayList();&lt;br /&gt;  }&lt;br /&gt;}&lt;/long&gt;&lt;/pre&gt;&lt;br /&gt;You can then transparently use the id-query in the complex case or issue the main query in the simple case:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  return criteria.list();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The presented approach has worked for me in a number of cases, and I am very happy now!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/25299220-4017784879369009146?l=floledermann.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://floledermann.blogspot.com/feeds/4017784879369009146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=25299220&amp;postID=4017784879369009146' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/4017784879369009146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/25299220/posts/default/4017784879369009146'/><link rel='alternate' type='text/html' href='http://floledermann.blogspot.com/2007/10/solving-hibernate-criterias-distinct.html' title='Solving Hibernate Criteria&apos;s &quot;Distinct Root Entity&quot; limitation once and for all - including pagination'/><author><name>Flo</name><uri>http://www.blogger.com/profile/13456675247042447579</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13692355615454251607'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>19</thr:total></entry></feed>