LIQUidFORM, an internal DSL for JPA queries, nears v1.0

Discussions

News: LIQUidFORM, an internal DSL for JPA queries, nears v1.0

  1. LIQUidFORM stands for Language Integrated QUeries For Object Relational Mapping and is a Java library that provides a Java Domain Specific Language for building type-safe and refactoring proof JPA queries. Suppose you have this : List people = em.createQuery( "SELECT FROM Person p WHERE p.surname LIKE 'Smith%'") .getResultList(); If you ever happen to rename the surname property to lastname, your IDE will certainly refactor your domain classes. But not the JPA Queries ! LIQUidFORM solves just that (and a little more). Its aim is to capture your intent when creating the query, so that when you change Person.getSurname() to Person.getLastName(), the query string gets updated as well. Here is how it goes : Person p = LiquidForm.use(Person.class, "p"); List people = em.createQuery( select(p).from(Person.class).as(p).where(like(p.getSurname(), "Smith%")).toString()) .getResultList(); As you can see, the framework offers a syntax that is very similar to the JPA query syntax. As a matter of fact, LIQUidFORM does very little: it just constructs a String representation of your query, just like you would by hand, that is in turn passed to your JPA engine of choice. But because in that construct p.getSurname() is an actual method call to the method named getSurname on the type Person, it will get refactored when you change surname to lastName. Of course, you also get other direct indications from your IDE when you perform other kinds of refactorings. For example, if you happen to delete the Person type, you'll be granted by a compile time error for sure. Something that would have gone unnoticed otherwise ! LIQUidFORM is licensed under the Apache Software License v2 and comes with extensive documentation, examples and tests. Download from http://code.google.com/p/liquidform or use the dedicated Maven repository.

    Threaded Messages (36)

  2. Criteria API[ Go to top ]

    Looks much better than JPA 2.0 Criteria API if I'm not mistaken. Can entity properties be field annotated?
  3. Nice idea, but ...[ Go to top ]

    I like your idea, but I guess this can only work well if you don't use field mapping, but getter/setter mapping? In my current project, there is at times quite a difference between the interface the entities provide and the way they are mapped internally. Could LiquidForm still be useful for us?
  4. Very similar to JaQu[ Go to top ]

    Almost the same API as JaQu (Java Query) that is included in the H2 Database Engine. I like it!
  5. Re: Very similar to JaQu[ Go to top ]

    Almost the same API as JaQu (Java Query) that is included in the H2 Database Engine. I like it!
    When did this happen?
  6. Re: Very similar to JaQu[ Go to top ]

    When did this happen?
    Do you mean since when I like it? :) I didn't know about LIQUidFORM before today. And I guess LIQUidFORM didn't know about JaQu before. The architecture is very different: JaQu uses reflection while LIQUidFORM uses CGLib/ASM. JaQu works with both getters/setters and fields, while LIQUidFORM only works with getters/setters currently. On the other hand, LIQUidFORM supports primitive types (boolean, int, long,..) while JaQu needs Boolean, Integer, Long fields. The target audience is very different: JaQu is a Hibernate replacement while LIQUidFORM/JPA just creates queries for JPA.
  7. Re: Very similar to JaQu[ Go to top ]

    When did this happen?


    Do you mean since when I like it? :) I didn't know about LIQUidFORM before today. And I guess LIQUidFORM didn't know about JaQu before.

    The architecture is very different: JaQu uses reflection while LIQUidFORM uses CGLib/ASM. JaQu works with both getters/setters and fields, while LIQUidFORM only works with getters/setters currently. On the other hand, LIQUidFORM supports primitive types (boolean, int, long,..) while JaQu needs Boolean, Integer, Long fields.

    The target audience is very different: JaQu is a Hibernate replacement while LIQUidFORM/JPA just creates queries for JPA.
    LOL. I meant when did you come out with JaQu.
  8. Re: Very similar to JaQu[ Go to top ]

    Oups, concurrent postings :) I concur with Thomas (although we were aware of JaQu). Small correction though : LIQUidFORM does not support primitives, sadly. (The library relies heavily on object identity (as in '==' ) and thus needs big objects. Thanks for your kind feedback
  9. I like it[ Go to top ]

    LIQUidFORM looks very cool and I like it :). I will surely give it a spin. Maurice
  10. Re: Very similar to JaQu[ Go to top ]

    we were aware of JaQu
    Good! I'm glad JaQu helped!
    LIQUidFORM does not support primitives
    So far :-) It's possible with getters. If you anyway create a proxy class, just log the method calling order. Example: where(p.getAge()).smaller(20)... where(20).smaller(p.getAge())... In the first case, p.getAge() is called just after where() but before smaller(), so you know it's age<20. In the second case getAge() is called after smaller(), so it must be 20<age. The problem is you can only use methods with one variable element, so smaller(a, b) doesn't work.
  11. Re: Very similar to JaQu[ Go to top ]

    @Thomas As a matter of fact, LIQUidFORM was inspired by JaQu (and other LINQ-like libraries) but while JaQu only targets H2 and kind of competes with ORM solutions (or more precisely, things like iBatis), we tried to leverage ORM solutions as much as we could. And indeed, it is not LINQ for Java : all it does is help you in building/refactoring your query which, at the end of the day is just .. a String.
  12. you can have field mappings[ Go to top ]

    I like your idea, but I guess this can only work well if you don't use field mapping, but getter/setter mapping
    This might not necessarily be true. Your entity mapping can still be mapped on the field, as you could possibly extend the entity bean object on the fly and override the getMethods. Hibernate uses the cglib to do lazy loading, it achieves this my overriding the get methods. The same principle could be applied here if it hasn't already done so. Imran
  13. @Anthavio: As a matter of fact, the intent of the project is not to mimic (or compete with) a criteria API. Although conditions have to use an ankward syntax, the initial goal is really to read like plain JPA. LIQUidFORM then just produces a plain String that is executed by your JPA implementation. @Anthavio, @Christophe: Support for field notation is in the works, not only for the cases you mention but also because parentheses are hard to read. I suppose you refer at eg providing addToMyCollection() and removeFromMyCollection() methods in you business interface while JPA is only concerned (privately) with get/setMyCollection(). Sadly, LIQUidFORM has to cope with Java "limitations" (method visibility) : it can't see what is private, and that is by design. All things being equal, the intent of the library is to help you where it can, and not hinder where it can't
  14. Ebean query[ Go to top ]

    I wonder if I broke this thread by posting with a pre tag? Seems to me some comments are not showing up? Anyway, my post said something like... With Ebean this query could be: List people = Ebean.find(Person.class) .where().like("surname","Smith%") .findList(); Automatic query tuning via "Autofetch" also could have a very big impact on ORM queries. Automatically tuning the query to specify joins and partial object loading based on profiling. I have been using this with Ebean for 6 months and its worked very well. Basically this means your queries do not need to specify joins or specific properties. For an intro go to: http://www.avaje.org/ebean/introquery_autofetch.html

  15. List people = em.createQuery(
    "SELECT FROM Person p WHERE p.surname LIKE 'Smith%'")
    .getResultList();

    If you ever happen to rename the surname property to lastname
    I am not sure I like the change, it does help the refactoring; but it make the SQL harder to read. I still like the native SQL's simplicity. In our project, we have enhanced the Query and EntityManager so that the above query can be easily written as List people = em.createNativeQuery(
    "SELECT p.firstName, p.surname as lastname FROM person_table p WHERE p.surname LIKE 'Smith%'", Person.class)
    .getResultList();
    People doesn't need to be an EJB 3 Entity Bean. As long as People has public setters for firstname and lastname (setFistname(),setLastname()), above query will proper populate returned objects.This is supported by current JPA. The enhancement allows nativeQuery takes Class argument just like QL. It can also use named argument, Map arguments etc. These enhancements are very simple to implement, I am surprised that JPA 1.0 did not include them in their first release.
  16. List people = em.createNativeQuery( "SELECT p.firstName, p.surname as lastname FROM person_table p WHERE p.surname LIKE 'Smith%'", Person.class) .getResultList();
    Hope your dba doesn't change your db naming conventions. :) BTW, you can do this pretty much with Hibernate and "Report Queries".
  17. List people = em.createNativeQuery(
    "SELECT p.firstName, p.surname as lastname FROM person_table p WHERE p.surname LIKE 'Smith%'", Person.class)
    .getResultList();

    Hope your dba doesn't change your db naming conventions. :)

    BTW, you can do this pretty much with Hibernate and "Report Queries".
    I am not sure what you mean by
    Hope your dba doesn't change your db naming conventions. :)
    If the naming convention is changed, either way you have to change: weather you changed in EJB3 column annotation or Hibernate mapping files. Here you change the SQL String. if the firstname is changed to FIRST_NAME, the code will be
    List people = em.createNativeQuery( SELECT p.FIRST_NAME as firstname, p.surname as lastname FROM person_table p where p.surname like 'Smith%', Person.class).getResultList();
    The result java code including Person class still the same without change. I know I can use Hibernate, but I prefer JPA.
  18. I am not sure what you mean by
    Hope your dba doesn't change your db naming conventions. :)
    Really? Ok, you have the table and columns hardcoded in your sql. If you change the db you have to find every place you use this as opposed to one place. This change has happened to me. We were done before the dba had the new database created. And we switched from Sybase (Linux) to DB2 (mainframe). All columns and tables had to change.
    I know I can use Hibernate, but I prefer JPA.
    What is the point if you are doing SQL and extending JPA anyway? If you need to do what you doing (fill put attributes in pojos) you can drop down to Hibernate and so some thing like this and still have the protection an ORM offers: Select new Person(p.firstName, p.surname) FROM Person as p WHERE p.surname LIKE :surname Now, if you can do what you are doing and use JPQL, then that would be pretty good. Not sure why you couldn't.
  19. I am not sure what you mean by
    Hope your dba doesn't change your db naming conventions. :)
    Really? Ok, you have the table and columns hardcoded in your sql. If you change the db you have to find every place you use this as opposed to one place. This change has happened to me. We were done before the dba had the new database created. And we switched from Sybase (Linux) to DB2 (mainframe). All columns and tables had to change.

    OK, now I understand your point. I have done that myself, in my previous project, we our against code, first ORACLE, then DB2, then MS SQL Server. Here we did were 1) Most if not all static SQL String are actually use constant field (static final String) and consolidated into few files (Such as PersistSQL.java). So search and find them is not a problem and only few know files are need to be searched. 2) There are very few cases where dynamic SQL need to have hard-coded Column; we do need to search, unfortunately. 3) For switch ORACLE -> DB2 -> MySQL Server, we use different approach. In most cases, the Column Names are the same for All database. Given there are different SQL flavor, we abstract the layer out so it can get different vendor specific syntax depends on the Database Vendor. These database vendor specific codes will be used for Date handling, number rows returned or other needs. And the SQL file structure files will be something like sql/oracle sql/db2 sql/sqlserver
    What is the point if you are doing SQL and extending JPA anyway? If you need to do what you doing (fill put attributes in pojos) you can drop down to Hibernate and so some thing like this and still have the protection an ORM offers:
    I have used Hibernate in previous project and EJB 3 Entity Bean with JPA with JPQL in current project. But in all the cases, I find both of them actually limiting. I did not want to bring this up in earlier discussion. I am sure there are a lot people with strong and different opinions on this. In both case, Hibernate or EJB Entity Bean will take me 95% of the way, and then fail me in 5% case unexpectedly. To resolve my 5% case, we have to rewrote entity bean or hiberate and not use ORM but populate ourself. This happened particularly when we want to do caching ourself. It is really annoying when you trying to get the object you cached, then OR Framework tell you the persistent context is no longer exist, you have to load it again. In other cases, the JPQL is not expressed enough to utilize what the underline database has to offer. We are strong believer that we should maximize the usage of underline database rather treat database as generic black box. After several projects like this. We concluded that we are better off directly write to Native SQL, populate the data ourself. JPA is great and we love it. Comparing with using JDBC, JPA is a joy. it is a bit more work than using JPQL at first . but not too much with JPA and Setter of POJO. Why do we have to extend JPA ? because, it doesn't have the nice support for native query as it did for JPQL. In JPQL, you can write List peoples = em.createQuery("select p from People p where p.surname = :surname", People.class).setParameter("surname,"MyLastName").getResultList(); In native query, you can only write : List results = em.createNativeQuery("select p from People p where p.surname = ? ").setParameter(1,"MyLastName").getResultList(); There is no Result (People.class) class, no named parameter and you have populate the result yourself. We enhanced the JPA and Enterprise Manager, so we can write List peoples = em.createNativeQuery("select p from People p where p.surname = :surname", People.class).setParameter("surname,"MyLastName").getResultList(); just like JPQL for the native query. The enhanced JPA Query can also take Array arguments for Native query. for example: String[] lastnames = new String[] {"yourlastname", "mylastname"}; List peoples = em.createNativeQuery("select p from People p where p.surname in (:surname...)", People.class).setParameter("surname",lastnames).getResultList(); It also can mix positioned parameter ("?") with named parameter (":surname") in one query. Regards, Chester
  20. Just to clarify my prev. post: NativeQuery can also take Class as send parameter, but you have to do cast List people =(List) em.createNativeQuery("...". People.class).getResultList();
  21. Select new Person(p.firstName, p.surname) FROM Person as p WHERE p.surname LIKE :surname
    If i am googling correctly, I it seems you can do this in JPQL too. So no need to drop to Hibernate.
  22. Hi, disclaimer: I'm a big fan of partial objects and as a consequence I see the lack of partial object support in JPQL as it's biggest design mistake.
    "SELECT p.firstName, p.surname as lastname FROM person_table p ...
    It maybe worth noting... this query could be written as a very simple "partial object" query if JPQL supported it. You should not have to go to native sql to perform such as query - its a shame no?
  23. I see the lack of partial object support in JPQL as it's biggest design mistake. You should not have to go to native sql to perform such as query - its a shame no?
    You can do that in standardised JDOQL and have been able to for a very long time.
  24. I see the lack of partial object support in JPQL as it's biggest design mistake. You should not have to go to native sql to perform such as query - its a shame no?

    You can do that in standardised JDOQL and have been able to for a very long time.
    So as an example, if we have a Person entity that has an Address entity ... and I only want to fetch the person firstName and surname and from the address only fetch the suburb and city. How do you do that in JDOQL? Can you show me an example? Aka in Ebean's query language this is: find person (firstName,surname) join address (suburb, city) where surname like :personSurname Thanks, Rob.
  25. Re: Partial Object support in JDOQL[ Go to top ]

    if we have a Person entity that has an Address entity ... and I only want to fetch the person firstName and surname and from the address only fetch the suburb and city. How do you do that in JDOQL?
    "SELECT firstName, surname, address.suburb, address.city FROM mydomain.Person WHERE surname = :mysurname"
  26. Re: Partial Object support in JDOQL[ Go to top ]

    Cool thanks!! ... and JPQL does not support this because ... whoops thinking out loud again, I didn't actually ask that :)
  27. Re: Partial Object support in JDOQL[ Go to top ]

    Cool thanks!! ... and JPQL does not support this because ... whoops thinking out loud again, I didn't actually ask that :)
    Because it does?
  28. it's about time[ Go to top ]

    ... a useful project has been posted. Sick of all the useless web and logging frameworks we see everyday
  29. Clear to unclear[ Go to top ]

    A good example to transform a clear syntax into an horrible one :-((
  30. Re: Clear to unclear[ Go to top ]

    A good example to transform a clear syntax into an horrible one :-((
    As has already been pointed out, your "clear syntax" is not refactorable so has a significant drawback, so as "clear" as it is, you have a maintenance overhead whenever you refactor. There's a place for string-based query languages (JDOQL, JPQL, SQL, etc), just as there is a place for refactorable query languages (whether LINQ, or JaQu, or db4o Native, or Liquidform, ...). They both have their own group of target users. You don't say "what" is horrible, but then perhaps if you had been used to object-based queries for many years and suddenly looked at some new "SQL" string-based syntax you would think Ughhhhh ...
  31. Re: Clear to unclear[ Go to top ]

    A good example to transform a clear syntax into an horrible one :-((

    As has already been pointed out, your "clear syntax" is not refactorable so has a significant drawback, so as "clear" as it is, you have a maintenance overhead whenever you refactor. There's a place for string-based query languages (JDOQL, JPQL, SQL, etc), just as there is a place for refactorable query languages (whether LINQ, or JaQu, or db4o Native, or Liquidform, ...). They both have their own group of target users.

    You don't say "what" is horrible, but then perhaps if you had been used to object-based queries for many years and suddenly looked at some new "SQL" string-based syntax you would think Ughhhhh ...
    Exactly. The problem is that most developers see everything as all or nothing (ie. "Java shop" or "Struts Shop").
  32. Re: Clear to unclear[ Go to top ]

    A good example to transform a clear syntax into an horrible one :-((
    Seems pretty clear to me.
  33. Ebean query[ Go to top ]

    In Ebean this query could be written as: List people = Ebean.find(Person.class) .where().like("surname","Smith%") .findList(); One thing to note is that Automatic query tuning (via Autofetch) could have a significant effect on ORM queries (by removing the need for explicit joins and adding automated partial object support). http://www.avaje.org/ebean/introquery_autofetch.html That is, for ORM's that support Autofetch a lot of what is currently defined manually in the query is provided by the ORM as part of its automatic query tuning process. I've been using this for 6 months now with Ebean and it works very nicely - reduces lazy loading etc. Cheers, Rob.
  34. 4GL[ Go to top ]

    I agree with the "horribleness" of the syntax. I can't imagine our complex HQL queries written this way. We urgently need a 4GL language based in Java which allows to write OQL queries, checking syntax, refactoring etc. I hate Hibernate criterias for the same reason, lack of readability.
  35. Re: 4GL[ Go to top ]

    select(p).from(Person.class).as(p).where(like(p.getSurname(), "Smith%")) versus select p from Person as p where p.surname like :surname Yeah, pretty horrible. Not. Not having tried refactor a complex HQL query to this syntax I would still believe that a complex HQL query might get ugly. I have tried to write complex Criteria queries and just went back to HQL. But this is different. Think about it. How many queries out of all queries that you do are that complex? Really? So do the simple ones in this and then do the really ugly complex ones in HQL. I don't know how many times I have screwed up typing strings. So the savings is not just in refactoring.
  36. Re: 4GL[ Go to top ]

    Why not just use SQL? A 4GL DSL with good readability. Hibernate/JPA just add an extra layer of complexity to your app.
  37. Re: 4GL[ Go to top ]

    Why not just use SQL? A 4GL DSL with good readability. Hibernate/JPA just add an extra layer of complexity to your app.
    LOL. Have you read any Hibernate books? HQL greatly reduces the complexity within the code. For instance, take the following HQL query - "from Measurement". Do you know what the corresponding SQL (and probably Java code) would/could be?