Help

There's been plenty of discussion in the JPA group about my typesafe criteria proposal. My new favorite feature of the Java language is javax.annotation.Processor. Java 6 annotation processors are derived from the APT tool that existed in JDK 5, but are built into javac. Really, the name annotation processor is misleading, since this feature is only incidentally related to annotations. The Processor is really a fairly general purpose compiler plugin. If, like me, you've never been a fan of code generation, now is the time to reconsider. A Java 6 Processor can:

  • analyze the compiler's metamodel of the Java source code that is being compiled
  • search the source path for other metadata, such as XML
  • generate new types, which will also be compiled, or other files

Best of all, this functionality requires no special tool or commandline options to javac. All you need to do is put the jar containing your Processor in the classpath, and the compiler does the rest!

In the typesafe query API, I want to use this to work around Java's lack of a typesafe metamodel for fields and methods of a class. The basic idea is that the compiler plugin will generate a metamodel type for each persistent class in the application.

Suppose we have the following persistent class:

@Entity
public class Order {
    @Id long id;
	
    boolean filled;
    Date date;

    @OneToMany Set<Item> items;

    @ManyToOne Shop shop;
	
    //getters and setters...
}

Then a class named Order_ would be generated, with a static member of each persistent attribute of Order, that the application could use to refer to the attributes in queries.

After several iterations, we've settled on the following format for the generated type:

import javax.jpa.metamodel.Attribute;
import javax.jpa.metamodel.Set;
import javax.jpa.metamodel.Metamodel;

@Metamodel
public abstract class Order_ {
    public static Attribute<Order, Long> id;
    public static Attribute<Order, Boolean> filled;
    public static Attribute<Order, Date> date;
    public static Set<Order, Item> items;
    public static Attribute<Order, Shop> shop;
}

The JPA provider would be responsible for initializing the values of these members when the persistence unit is initialized.

Now, criteria queries would look like the following:

Root<Item> item = q.addRoot(Item.class);
Path<String> shopName = item.get(Item_.order)
                            .get(Order_.shop)
                            .get(Shop_.name);
q.select(item)
 .where( qb.equal(shopName, "amazon.com") );

Which is equivalent to:

select item 
from Item item
where item.shop.name = 'amazon.com'

Or like:

Root<Order> order = q.addRoot(Order.class);
Join<Item, Product> product = order.join(Order_.items)
		                   .join(Item_.product);
		
Path<BigDecimal> price = product.get(Product_.price);
Path<Boolean> filled = order.get(Order_.filled);
Path<Date> date = order.get(Order_.date);
		
q.select(order, product)
 .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) )
 .order( qb.ascending(price), qb.descending(date) );

Which is equivalent to:

select order, product 
 from Order order 
    join order.items item
    join item.product product
 where
    product.price > 100 and not order.filled
 order by
    product.price asc, order.date desc

The queries are almost completely typesafe. Because of the generic type parameters of Attribute:

  • I can't pass an attribute of Order to a Join or Path that represents an Item, and
  • I can't try to perform a comparison like gt() on a Path that represents a boolean attribute, or not() on a Path that represents an attribute of type Date.

There's some skeptics in the expert group, but my feeling is that once people get used to the idea that type generation is no longer something that gets in your way during development, we're going to see a lot more frameworks using this kind of approach. I certainly think this API is a big improvement over the previous proposal:

Root item = q.addRoot(Item.class);
Path shopName = item.get("order")
                    .get("shop")
                    .get("name");
q.select(item)
 .where( qb.equal(shopName, "amazon.com") );

Or:

Root order = q.addRoot(Order.class);
Join product = order.join("items")
		    .join("product");
		
Path price = product.get("price");
Path filled = order.get("filled");
Path date = order.get("date");
		
q.select(order, product)
 .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) )
 .order( qb.ascending(price), qb.descending(date) );

Both these queries are riddled with non-typesafe method invocations which can't be validated without executing the query.

42 comments:
 
21. Dec 2008, 17:42 CET | Link

How about posting the code for the processor ? :)

 

--max

ReplyQuote
 
21. Dec 2008, 18:28 CET | Link
Max Andersen wrote on Dec 21, 2008 11:42:
How about posting the code for the processor ? :)

Actually I was hoping you could write it :-)

 
22. Dec 2008, 09:40 CET | Link
Will this proposal require the programmer to compile Order with an external tool before writing the queries? How will the editing experience in an IDE feel?

An alternative approach that doesn't require code generation is to use dynamic proxies in the same style as Mockito (http://code.google.com/p/mockito/). This avoids all code generation and preserves compile type typing and autocompletion. Also, notice the absence of static method calls. Here a conceptual preview that can capture the necessary information:

queryBuilder = new QueryBuilder();
Employee employee = queryBuilder.createQueryDefinition(Employee.class);
queryBuilder.where(employee.getContactInfo().getAddress().getZipCode()).eq("95054")
    .where(employee.getContactInfo().getPhones().get(0).getPhoneType()).eq(PhoneType.OFFICE)
    .selectDistinct(employee.getContactInfo().getPhones().get(0).getBilledTo());


Here's a more complex example of the same approach:

queryBuilder = new QueryBuilder();
customer = queryBuilder.createQueryDefinition(Customer.class);
queryBuilder.caseExp(customer.getAnnualSpending())
    // Please note: The compiler stops us from saying e.g. gt("ten thousand")
    .when().gt(10000.0).then("Premier")
    .when().gt(5000.0).then("Gold")
    .when().gt(200.0).then("Silver")
    .otherwise("Bronze");

 
22. Dec 2008, 10:02 CET | Link
Will this proposal require the programmer to compile Order with an external tool before writing the queries?

No, absolutely not, as I wrote above: this functionality requires no special tool or commandline options to javac.

i.e. no tool at all, except for the standard Java compiler. It's a built-in feature of the language.

How will the editing experience in an IDE feel?

Eclipse already has built-in support for this stuff and it feels really seamless.

An alternative approach that doesn't require code generation is to use dynamic proxies in the same style as Mockito (http://code.google.com/p/mockito/). This avoids all code generation and preserves compile type typing and autocompletion. Also, notice the absence of static method calls.

There is a major problem with this approach (which is also used in liquidforms), and also a minor problem:

  1. all persistent attributes must be modeled as public getter methods. This is simply not acceptable in the context of JPA, which supports persistent properties and fields of any visibility.
  2. nothing stops you from trying to refer to @Transient attributes or derived properties. Not a huge problem in most cases, but annoying.

These two problems demonstrate that the set of public getter methods of the class are simply not a good model of the set of persistent attributes.

The solution I've proposed to the JPA group solves the problem by having a type where the public attributes really do correspond to the persistent attributes.

 
22. Dec 2008, 12:57 CET | Link

Really like this idea - improved type safety means catching more errors sooner at compile time rather than runtime.

I've been thinking of writing something similar for a while for JavaBean properties for doing UI binding, etc.

One issue with using annotation processors for generating code for entities: what happens if your entities already exist as class files, e.g. different team writing them perhaps or the classes already exist and we've used XML mappings? As far as I can see, annotation processors only run over source code - if this is the case will an alternative exist that can run over compiled class files? I wonder how many developers are actually in this situation (is it worth writing an equivalent generator that runs over class files if hardly anyone would use it or is it worth doing for the sake of completeness)?

 
22. Dec 2008, 13:35 CET | Link
One issue with using annotation processors for generating code for entities: what happens if your entities already exist as class files, e.g. different team writing them perhaps or the classes already exist and we've used XML mappings? As far as I can see, annotation processors only run over source code - if this is the case will an alternative exist that can run over compiled class files? I wonder how many developers are actually in this situation (is it worth writing an equivalent generator that runs over class files if hardly anyone would use it or is it worth doing for the sake of completeness)?

I imagine that it would be slightly useful to provide this (and easy enough to do). However, in almost all cases, I see the metamodel classes being provided by the team writing the entity classes.

 
23. Dec 2008, 05:23 CET | Link
Mike Youngstrom | youngm(AT)gmail.com

I like it.

I especially like the whole idea of a JPA metamodel in general as a way to problematically reflect upon the Entity Model. I would love in JPA, for example, to be able to determine the PK of an entity without having to do my own orm.xml parsing and annotation reading. I believe a meta model would be a great boon for JPA addon libraries and frameworks. I think this typesafe criteria API is simply one excellent example of what could be done with a JPA metamodel.

 
23. Dec 2008, 12:53 CET | Link
No, absolutely not, as I wrote above: this functionality requires no special tool or commandline options to javac.

Nice, thanks. I will have to investigate Processor some more.

These two problems demonstrate that the set of public getter methods of the class are simply not a good model of the set of persistent attributes.

Actually, the first problem (having to use accessors) isn't as bad as you could expect. Only properties that are to be part of the queries need to be public. This is not an unexpected concession, at the client most likely want to query the public interface. This is compatible with fields being mapped as long as queryable fields also have accessors. But that's a small point.

More interestingly, perhaps: Havr you considered price.gt(1000.0) rather than qb.gt(price, 1000.0)? (gt would be a method on Attribute. This would possibly read better, reduce the number of places thar depend on the QueryBuilder (although, as the dependency cannot be removed completely, this is probably a fools errand) and, most importantly, probably be more code completion friendly.

 
24. Dec 2008, 02:32 CET | Link
Walter Harley | eclipse(AT)cafewalter.com
How will the editing experience in an IDE feel? Eclipse already has built-in support for this stuff and it feels really seamless.

I'm glad to hear that you're finding the Processor support in Eclipse to be seamless! Speaking as the author, though, there are a few gotchas worth mentioning.

When using the Eclipse command-line compiler (ecj) the experience is very close to javac (arguably better in some regards). In the IDE, though, annotation processing is seamier. You can not just put the processor on the classpath; it has to go into a separate path, called the Factory Path, or else it can be in a plug-in. This is because of the difficulty of unloading the jar after a processor has been loaded from it. Also, there are a number of APT APIs that are still unimplemented in the IDE, although I'm working on that. Finally, while Java 5 annotation processors are run as you make changes in an editing session, Java 6 processors are run only when you do a build; thus, code won't be (re)generated until a build, which means that when you change an annotation you won't see the effects until you build.

Finally, developers should be aware that while the JSR-269 API (javax.lang.model, javax.annotation.processing) is standardized and is available in both Eclipse and javac, it only gives access to the metamodel (as you mentioned); for many tasks this is inadequate. Unfortunately, to access the code itself, you need to use either the DOM AST in Eclipse, or the Tree API in javac; these are completely different and incompatible APIs.

Some of these seams are by design, some are because of limited development resources. If you or anyone exploring this feature runs into issues, please report them via Eclipse's Bugzilla or in the eclipse.tools.jdt newsgroup; seams notwithstanding, the project is still being actively, albeit slowly, worked on, and bugs are fixed as they get reported. Thanks!

24. Dec 2008, 04:19 CET | Link

This looks very much like unbound Properties. It also reminds me of the field literals from the FCM closures proposal. This same technique could be used for typesafe reflection. I like it, using raw strings is always asking for trouble.

 
24. Dec 2008, 05:18 CET | Link

Hi Walter,

The biggest issue I have right now is to even get the Java 6 annotation processor to be picked up properly in Eclipse 3.4 - do you have a working workspace/example ? The latest eclipsecon slides contain the skeleton of a java 6 processor but I never can seem to get it launched ;( Any tips on debugging (besides system.out.println :)

/max

 

--max

24. Dec 2008, 12:58 CET | Link

Well, it's not a general purpose attribute literal syntax, since it's specific to the JPA mapping metadata (i.e. you don't get literals representing @Transient or derived attributes).

However, I certainly think that this approach could be applicable in other areas, especially databinding. (For example, I think that Wicket's databinding could be significantly improved using this idea.

 
24. Dec 2008, 13:05 CET | Link
Walter Harley wrote on Dec 23, 2008 20:32:
Also, there are a number of APT APIs that are still unimplemented in the IDE, although I'm working on that.

Which ones exactly? If they're obscure ones, I doubt they will affect the JPA usecase, which is pretty straightforward.

Finally, while Java 5 annotation processors are run as you make changes in an editing session, Java 6 processors are run only when you do a build; thus, code won't be (re)generated until a build, which means that when you change an annotation you won't see the effects until you build

So it would be great if this could be fixed. I'm assuming that there is not a conceptual problem here, since it works for the Java 5 API.

Finally, developers should be aware that while the JSR-269 API (javax.lang.model, javax.annotation.processing) is standardized and is available in both Eclipse and javac, it only gives access to the metamodel (as you mentioned); for many tasks this is inadequate. Unfortunately, to access the code itself, you need to use either the DOM AST in Eclipse, or the Tree API in javac; these are completely different and incompatible APIs.

Right, but for the JPA usecase, this is just not an issue.

 
24. Dec 2008, 15:02 CET | Link
Walter Harley | cafewalter(AT)gmail.com
Max Andersen wrote on Dec 23, 2008 23:18:
The biggest issue I have right now ...

I'm eager to help, but let's take it up on the eclipse.tools.jdt newsgroup rather than in Gavin's blog.

 
24. Dec 2008, 15:09 CET | Link
Walter Harley | cafewalter(AT)gmail.com
Which (APIs) exactly? If they're obscure ones, I doubt they will affect the JPA usecase, which is pretty straightforward.

Well, my hope is that they are obscure. One person's obscure is another's critical... I think the JPA usecase is probably safe, but if you run into anything, report it and I'll fix it.

So it would be great if (reconcile-time processing) could be fixed. I'm assuming that there is not a conceptual problem here, since it works for the Java 5 API.

This one is harder. There is no problem in principle but there are problems in practice. Even in the Java 5 case there are a lot of weirdnesses that stem from trying to generate new types at reconcile time; but the biggest problem is that it is very hard to write a processor that is deterministically fast. The compiler's job is to resolve as little typesystem information as possible to generate code, and it's quite good at that. The APT API's job is to be an omniscient oracle of the typesystem, and that job is incompatible with good compiler performance.

As an example, we encountered processors that tried to validate that a particular annotation appeared on only one type in a given package. This is incredibly expensive in the Eclipse compiler, particularly if the overall typesystem is larger than can fit in cache. It's easy to find positive information, expensive to find negative information. This one is perhaps obvious, but there are other missteps that can easily make a processor run too slowly to be acceptable at reconcile time.

I've gotten a couple requests so this may be resurrected, but probably not in the near term unless others wish to contribute resources. It's not insurmountable but there are a lot of little gotchas to work through, and APT is no longer my day job - I have time for bug fixes but not for major feature work.

 
25. Dec 2008, 08:17 CET | Link

Here is a similar reasonable stable project which provides typesafe, code complete friendly JPAQL/HQL queries. We use APT code generation as well.

http://source.mysema.com/display/querydsl/Querydsl

With Querydsl the following Root<Order> order = q.addRoot(Order.class); Join<Item, Product> product = order.join(Order_.items) .join(Item_.product); Path<BigDecimal> price = product.get(Product_.price); Path<Boolean> filled = order.get(Order_.filled); Path<Date> date = order.get(Order_.date); q.select(order, product) .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) ) .order( qb.ascending(price), qb.descending(date) );

becomes HqlQuery query = new HqlQuery(session); QOrder order = new QOrder("order"); QProduct product = new QProduct("product"); query.from(order).innerJoin(order.items.as(product)) .where(product.price.gt(100.00).and(not(order.filled))) .orderBy(product.price.asc(), order.date.desc()) .select(order, product);

The main two benefits are infix operator and property chaining.

What do you think?

 
25. Dec 2008, 08:35 CET | Link
Timo Westkamper

Here is a similar reasonable stable project which provides typesafe, code complete friendly JPAQL/HQL queries. We use APT code generation as well.

http://source.mysema.com/display/querydsl/Querydsl

With Querydsl the following

Root<Order> order = q.addRoot(Order.class); 
Join<Item, Product> product = order.join(Order_.items).join(Item_.product); 
Path<BigDecimal> price = product.get(Product_.price); 
Path<Boolean> filled = order.get(Order_.filled); 
Path<Date> date = order.get(Order_.date); 
q.select(order, product)
 .where( qb.and( qb.gt(price, 100.00), qb.not(filled) ) )
 .order( qb.ascending(price), qb.descending(date) );

becomes

HqlQuery query = new HqlQuery(session); 
QOrder order = new QOrder("order"); 
QProduct product = new QProduct("product"); 
query.from(order).innerJoin(order.items.as(product))
 .where(product.price.gt(100.00).and(not(order.filled)))
 .orderBy(product.price.asc(), order.date.desc())
 .select(order, product);

The main two benefits are infix operator and property chaining.

What do you think?

26. Dec 2008, 02:34 CET | Link
Gavin King wrote on Dec 24, 2008 06:58:
Well, it's not a general purpose attribute literal syntax, since it's specific to the JPA mapping metadata (i.e. you don't get literals representing @Transient or derived attributes).

Hi Gavin,

first of all, I like the idea of generating field literals (though I would prefer them to be part of the language - as in the FCM closure prototype mentioned by Collin).

Is there any specific reason for the restriction on JPA entities? As you already wrote, there are plenty of scenarios, in which type-safe field literals would be convenient. One could introduce an annotation like @CreateFieldLiterals to tag any class, for which a corresponding meta model class should be generated.

The name of the meta model class ending with a "_" looks a bit strange in my eyes. How about the following:

public class OrderAttributes {
        public static Attribute<Order, Long> Order_Id;
        public static Attribute<Order, Boolean> Order_Filled;
        public static Attribute<Order, Date> Order_Date;
        public static Set<Order, Item> Order_Items;
        public static Attribute<Order, Shop> Order_Shop;
}

By importing statically OrderAttributes.* one could refer to the attributes by Order_Id instead of Order_.id etc.

Does already some more formal specification of the proposal exist, e.g. what is the intention for the special treatment of the items set in your example (Set<Order, Item> instead of Attribute<Order, Set<Item>>)?

Are there already any efforts underway to implement the required annotation processor?

With kind regards,

Gunnar

 
27. Dec 2008, 14:45 CET | Link
Johannes Brodwall wrote on Dec 23, 2008 06:53:
More interestingly, perhaps: Havr you considered price.gt(1000.0) rather than qb.gt(price, 1000.0)? (gt would be a method on Attribute. This would possibly read better, reduce the number of places thar depend on the QueryBuilder (although, as the dependency cannot be removed completely, this is probably a fools errand) and, most importantly, probably be more code completion friendly.

Actually I think it reads much worse. In mathematics, operations like eq(), + and * are symmetric (and some of them are also associative). I've always hated trying to read crap like: 1.plus(2), which obfuscates the symmetry of the operator, and tends to lead to paren counting problems when you get to )))) at the end of the line.

Furthermore, it's not possible in a typesafe API, since some operators apply to, e.g. Expression<String>, or Expression<Boolean>, we can't just throw them onto Expression as methods.

 
27. Dec 2008, 14:48 CET | Link
The main two benefits are infix operator and property chaining.

Again, infix operations are a bad idea, unless Java supported operator overloading.

Property chaining is kinda nice.

27. Dec 2008, 14:50 CET | Link
what is the intention for the special treatment of the items set in your example (Set<Order, Item> instead of Attribute<Order, Set<Item>>)?

In JPA-QL/HQL, and in this API, joining a collection is a very different operation to joining a single-valued association. Furthermore, collection-valued attributes cannot be navigated in path expressions.

27. Dec 2008, 14:51 CET | Link

Does already some more formal specification of the proposal exist?

Yes. It's almost finished.

29. Dec 2008, 21:16 CET | Link

Thanks Gavin, interesting work.

My humble opinion: We really want to have LINQ for Java instead. We are falling behind the .NET world if we don't develop a strong typesafe standard for querying in Java.

 
02. Jan 2009, 23:42 CET | Link

begin-rant This is (yet) another place where we are getting around the lack of first class property support in Java.

Until recently it was only the people doing binding to Swing (or SWT) fields that had a demonstrable need for first class property support, but with the Criteria API on JPA its a database issue as well.

There exists a full implementation of a very adequate first class property support, as a set of patches against OpenJDK 7.0. Yes one might debate the detail, but surely we are now at the point where the principle of the thing needs to be accepted and implemented.

To me Java has always had the enormous advantage that its strong typing made is hard to write wrong code - and this is a VERY good thing. Having string field names in binding code (of whichever type) removed type safety and coder safety.

I know that Sun seem to have made their minds up that first class property support should not be added to Java 7, and also that it will be long time before we even get Java 7 (and I do not want to prolong that more than necessary), but the lack of first class property support has got beyond a joke and is becoming a millstone, reducing Java to the level of scripting languages where you could never tell if you had written the right thing until the user tried it.

We need to fight back, and force (if necessary by forking OpenJDK 7 and persuading the likes of Eclipse to come with us) Sun to do the right thing and adopt first class property support. end-rant

David

ps, if anyone wants to read some of my other rantings on the subject, they can be found on my blog at http://dga.co.uk/blog.

 
28. Jan 2009, 15:57 CET | Link
1.plus(2) obfuscates the symmetry

True. What about:

.where(price).gt(100.00)

symmetric, shorter, and clearer than:

.where(qb.gt(price, 100.00))

Did you have a look at JaQu?

P.S. I didn't know about Processor and JPA 2.0 so far.

 
01. Jul 2009, 00:04 CET | Link
Stephen Haberman | stephen(AT)exigencecorp.com
However, I certainly think that this approach could be applicable in other areas, especially databinding.

On that note, I was prototyping a processor that generates these types of bindings when you wrote this. It's pretty solid now, though doesn't have many users.

There is a description of it at:

http://joist.ws/bindgen.html

And the 2nd screencast at:

http://joist.ws/bindgen.html

I haven't done much promotion/blogging on it. Probably should do more and see what people think of it.

 
18. Jul 2009, 13:31 CET | Link
Robert Nice
It amazes me the pain and suffering that people are going to to bolt property literals/pointers into Java. Why go to all the effort, so many people refuse to put in property references, it's obvious nobody wants this (a little sarcastic).

I've got to agree with DGA above. Something like:

Root<Order> order = q.addRoot(Order.class);
Join<Item, Product> product = order.join(Order#items).join(Item#product);

instead of the given example. The benefit of it working across all compilers without having to know how to decode your specific class/generic setup by loading a plugin seems to make more sense. Having to reference transformed code in pre-transformed code seems to be a bit dangerous (Order.xyz vs. Order_.xyz vs. Order#xyz), or is this handled by the compiler also? What if I'm just putting a transformed jar into another project, can it figure all this out? Talk about a complicated way of doing something simple.
 
28. Nov 2009, 01:25 CET | Link
Stephen Haberman | stephen(AT)exigencecorp.com

Following up on your UI/wicket data binding comment, Igor Vaynberg started a bindgen-wicket project that integrates bindgen with Wicket.

 
12. May 2010, 03:36 CET | Link

I'm reviving an old thread, but just now I'm starting to use JPA 2 and the criteria API.

Gavin King wrote on Dec 27, 2008 08:45:
Actually I think it reads much worse. In mathematics, operations like eq(), + and * are symmetric (and some of them are also associative). I've always hated trying to read crap like: 1.plus(2), which obfuscates the symmetry of the operator, and tends to lead to paren counting problems when you get to )))) at the end of the line. Furthermore, it's not possible in a typesafe API, since some operators apply to, e.g. Expression<String>, or Expression<Boolean>, we can't just throw them onto Expression as methods.

I don't think that 1.plus(2) is crap, or Java is just crap: Take java.lang.Object.equals(other) - equals is symmetric too. It's incalculable the number of java programmers affected by such a 1.plus(2) is crap, and will have to deal with hard to read programs for their life because of this.

I just can't imagine how can someone think that:

Root<User> u = query.from(User.class);
query.where(
    cb.equal(u.get(User_.group).get(Group_.name), group),
    cb.equal(u.get(User_.username), username)
)

Is more legible than:

User_ u = query.from(User_.class);
query.where(
    u.group.name.equal(group),
    u.username.equal(password)
)

And this is just a VERY simple query...

Also, to work through the problems with Expression<String> and Expression<Boolean>, with would be possible to create things like StringExpression, BooleanExpression, TemporalExpression ... so, in the example, User_.username would be a StringExpression, and User_.username.like("John%") would be valid, but User_.activationDate.like("John%") not.

 
12. May 2010, 05:12 CET | Link

You're a bit mixed up here. The extra legibility in your code example is not coming from anything to do with use of infix operators vs prefix operators. Rather it is coming from the fact that you're dereferencing attributes directly upon User_, instead of going via Root<User>. The reason for the use of Root<User> has nothing to do with operator symmetry (a completely different set of considerations went into that choice).

So, to get to a fair comparison of the two approaches, you would need to re-write my code example as:

User_ u = query.from(User_.class);
query.where(
    cb.equal(u.group.name, group),
    cb.equal(u.username, username)
)

or, alternatively, you would need to re-write your code example as:

Root<User> u = query.from(User.class);
query.where(
    u.get(User_.group).get(Group_.name).equal(group),
    u.get(User_.username).equal(password)
)

In which case the version with the infix operator is not clearly more legible. To me they're about equal in terms of verbosity.

What your code examples are really showing is that you can get less verbose code by making User_ extend Root. But unfortunately, you then start running into other problems. For example, what type corresponds to a Join<User> in your API? How do you distinguish between a Root and a Join when all you have is User_? You would end up having to generate UserRoot, UserFrom, UserPath and UserJoin types in addition to the static metamodel User_.

Now, if you feel it is worth your time, you could certainly write a smart annotation processor for JPA2 to generate all these extra types as wrappers over what JPA provides as part of the spec. We didn't want to go there as part of this revision of the JPA spec. Instead, we wanted to really limit the use of code generation to just the very minimum that was needed in order to create a typesafe API, leaving other folks free to experiment with solutions that involve more aggressive code generation.

Also, to work through the problems with Expression<String> and Expression<Boolean>, with would be possible to create things like StringExpression, BooleanExpression, TemporalExpression ...

Of course we experimented with this approach but we pretty quickly rejected it because of the combinatorial profusion of types involved once you start getting to have to deal with collections.

We really did think this stuff through. :-)

 
24. Jan 2011, 13:09 CET | Link
maya

please could you tel , which jar files support this interfaces , import javax.jpa.metamodel.Attribute; import javax.jpa.metamodel.Set; import javax.jpa.metamodel.Metamodel; also could you tel ,actually we are implemented hibernate with jpa with mapping used xml configuration(persistence.xml) not using annotations. could you tel how i can use Dynamic, typesafe queries in JPA 2.0 with mapping xml configuration.

Thanks and regards maya

06. Jul 2014, 11:06 CET | Link

The Michael Fiore Text Your Ex Back 2.0 PDF and multimedia texting system is here! Read reviews, get download and purchase links, and learn about Michael Fiore text examples and techniques to get your ex back.best text to get your ex back

25. Jul 2014, 12:43 CET | Link

This site is a leading resource for information about the Robert Ford Winning The One PDF book and commitment guide that teaches you how you can take almost any relationship and turn it around and have a life full of passion, love, caring, and fun with a man who is fully committed and willing to do anything to keep you.winning the one pdf

27. Jul 2014, 08:41 CET | Link

Includes a collection of Rusty Moore Visual Impact Muscle Building reviews, PDF download information, and tips and exercises from around the web for staying lean, fit, and strong all year long.visual impact muscle building

10. Sep 2014, 22:16 CET | Link
asadalikhatri

Well, this got me thinking what other workouts are good for those of us who find ourselves on the road or have limited equipment options.home workout

 
11. Sep 2014, 14:49 CET | Link
asadalikhatri

Thanks for sharing this interesting blog with us.My pleasure to being here on your blog..I wanna come beck here for new post from your site. upper serangoon view condo

12. Sep 2014, 12:00 CET | Link

Manifestation Miracle by Heather Mathews is a digital product and can be downloaded instantly after purchase in PDF (ebook) format or viewed directly online using your favorite web browser.https://rebelmouse.com/manifestationmiraclereviews/

14. Sep 2014, 08:08 CET | Link

Includes a collection of Michael Fiore Text The Romance Back reviews, PDF download information, and romantic texting tips from around the web.michael fiore text the romance back method

16. Sep 2014, 10:23 CET | Link

Gain instant access to the natural and weird anti-inflammatory system for safely and permanently shrinking and eliminating nasal polyps with the help of world-renowned bio-medical researcher, health consultant, nutritionist, and author, Manuel Richards.can nasal polyps be removed without surgery

17. Sep 2014, 10:59 CET | Link

The Customized Fat Loss For Men program is compatible with desktop and laptop computers, iPhones, iPads, and virtually any tablet, smart phone, or other device that has PDF viewing capabilities.how do i keep my body in fat burning mode

 
17. Sep 2014, 14:50 CET | Link
asad

This is an excellent post I seen thanks to share it. It is really what I wanted to see hope in future you will continue for sharing such a excellent post.Daniel negreanu poker strategy

20. Sep 2014, 10:49 CET | Link

The first is the program you see here on this site, Restore My Vision Today (sometimes also called Perfect Vision Today) by Dr. Sen and Samantha Pearson which was just recently released in April 2014. The second is called Vision Without Glasses by Duke Peterson which has been around for years, is extremely popular, and is currently ranked as the 1 natural vision improvement guide in the Clickbank Marketplace.samantha pearson restore my vision today system

Post Comment