18

In C# you can enclose a lambda expression in an expression tree object and then possibly parse it. I was wondering if this is also possible in Java?

What I'm looking for is doing something like this:

BooksRepository.getAll()
.where(b -> b.getIban() == "SomeIban")
.and(b -> b.getAuthor() == "SomeAuthor"); //etc.

And then the BooksRepository should somehow translate that query to the following RESTful API request based on the predicates specified as lambdas:

GET http://mylibrary.com/books?Iban=SomeIban&Author=SomeAuthor

and then return the result to the client. Any idea if this is even possible in Java?

Eyad
  • 327
  • 3
  • 10
  • 5
    That's a noble goal, but lambdas will not help you with it at all. Nothing comparable exists in Java. – Marko Topolnik Sep 23 '14 at 07:47
  • @MarkoTopolnik When I asked the question I was not sure whether this is possible in Java or not, just now, I came across [jinq](https://github.com/my2iu/Jinq). which suggests that this _is_ doable in Java! – Eyad Sep 23 '14 at 07:50
  • Of course it is *doable* in Java, if you want to write the complete implementation, starting from the code parser. For that matter, it is *doable* to implement `gcc` in Java. But it is not something Java provides. – Marko Topolnik Sep 23 '14 at 07:53
  • I have taken a quick look at JINQ and I don't see any trace of the feature you have in mind here. It is just a hard-coded SQL implementation with a LINQ-like API. – Marko Topolnik Sep 23 '14 at 07:56
  • 1
    What’s the advantage of writing `.where(b -> b.getIban() == "SomeIban")` instead of `WHERE IBAN = 'SomeIban'` (as part of an SQL statement)? It would be powerful if it could translate arbitrary Java code but the corresponding C# feature is limited to simple expressions so it stops right where it could start to become useful… – Holger Sep 23 '14 at 08:03
  • @MarkoTopolnik I'm still not entirely sure how it works, but it seems like it **translates** stream/lambda expressions to a query statement of a different syntax. For a hint, read about Translatables in http://www.jinq.org/docs/queries.html – Eyad Sep 23 '14 at 08:04
  • You're confusing lambda expressions with LINQ. LINQ is used with lambda expressions and from what I can tell you're looking for a Java alternative to LINQ, not to C# lambdas – user Sep 23 '14 at 08:14
  • 5
    @Holger The advantage is avoiding opaque, non-syntax-checked strings. But I would prefer jOOQ any day to this, because with that approach you can have *reusable* parts of SQL represented in Java objects. On the other hand, that approach is specific to SQL and is not what OP is asking about here. – Marko Topolnik Sep 23 '14 at 08:18
  • 3
    @Holger refactoring, compilation time checks, auto-completion and abstraction of the underlying query implementation. – Eyad Sep 23 '14 at 08:23
  • 1
    @Eyad You get abstraction from the underlying query implementation with any other tech as well, such as JPA, Hibernate, jOOQ, ... – Marko Topolnik Sep 23 '14 at 08:24
  • 1
    @Marko Topolnik: well, you get a syntax check at compile time regarding the Java syntax but whether that syntax can be translated to the database query cannot be checked at compile time. In the end the constructs are a) too trivial to bother or b) a big performance killer if you ignore how the underlying storage really works. – Holger Sep 23 '14 at 08:25
  • @Eyad: as said, that would make sense if more than just trivial expressions were supported. – Holger Sep 23 '14 at 08:27
  • Absolutely, I only said that because @Holger was asking about the advantage of doing that compared to writing the actual "underlying query implementation". – Eyad Sep 23 '14 at 08:27
  • 3
    @Holger Agreed, especially your point in the first sentence. The lambda can be anything and only the runtime will hit you with an error. Even worse, it seems that the runtime will "seamlessly" revert to in-JVM processing. Y-U-C-K. – Marko Topolnik Sep 23 '14 at 08:28
  • @Holger It's up to me to decide how advanced my query (translator) should be. Again, looking back at .Net, I would imagine that something like [linq to amazon](http://weblogs.asp.net/fmarguerie/Introducing-Linq-to-Amazon) is less powerful than [linq2sql](http://msdn.microsoft.com/en-us/library/bb882680(v=vs.110).aspx) – Eyad Sep 23 '14 at 08:31
  • 1
    @Eyad Just my opinion, but LINQ pushes the extensibility of syntax over a sane limit. This kind of stuff is much more natural for a LISP than a CFG-based language. – Marko Topolnik Sep 23 '14 at 08:34
  • @Eyad: of course, if you implement it yourself, it’s up to you. But you asked for the existing support in Java and included a reference to the C# feature. And that feature is rather limited. And if there was a built-in support in Java it was *not* up to you to decide how far that support goes. Well, if you are beyond the point of asking for built-in support, your question has become meaningless. – Holger Sep 23 '14 at 08:35

4 Answers4

10

Yes, it's possible. I made a library that does exactly that: JaQue

Konstantin Triger
  • 1,576
  • 14
  • 11
  • 1
    This is remarkable and I'm really sad to see that this project has gotten so little attention and appears to be abandoned. LINQ is one thing, but I think Expressions are one of the most powerful features of C# and .NET and the ability to do type-safe, fluent configuration is incredibly powerful and expressive. – Avi Cherry Apr 28 '17 at 00:42
  • @AviCherry: thanks for your comment. If you think the project is important, you may vote here and in some linked questions on the right. Hopefully it will make it more visible. BTW, it's not dead. I simply don't have any open item on it ;-). After all, it's a library with a well defined API. The API is implemented, tests written, several bugs reported and fixed. – Konstantin Triger Apr 29 '17 at 18:15
9

I'm the author of Jinq. The automatic conversions of lambdas into expression trees that can be read at runtime is a C# only feature. That feature doesn't really have any general-purpose use for normal programmers. It's basically only useful for implementing LINQ, so language designers haven't been keen on adding that feature to Java or other languages. There has been talk of adding some sort of compiler plugin framework for Java that would allow you to add the expression tree feature to Java yourself, but I'm not too familiar with progress on that project.

Jinq contains a bytecode analysis framework that can build simple expression trees from the bytecode of a lambda at runtime. It is based on symbolic execution and ASM. It can be used to convert lambdas into expression trees, just like C#, but it's pretty heavy weight procedure with a lot of hoops to jump through, so it might be overkill for what you want to do. You'd be swatting a fly with a hammer, essentially.

There are languages other than Java that run on the JVM that have better support for the metaprogramming that you want to do. So you might also want to consider looking at Groovy or Scala for that.

Ming-Yee Iu
  • 844
  • 6
  • 5
  • Hi Dr. Ming. You are absolutely right in saying that if this was my only requirement then I would be "swatting a fly with a hammer", but it is not. Actually, the example I gave in the question was just a simple use case of many other things that I have in mind as we are moving towards java 8 from two way object mapping (ala automapper), validation rules (ala fluent validation.net), to workflow DSLs in addition to abstract RESTful queries. – Eyad Sep 25 '14 at 05:58
  • Oh, and BTW, I've read your article about symbolic execution and have been (trying) to understand of the analysis package of jinq (very impressive work by the way), but that was quite challenging for me being new to the whole java world. Do you happen to have any sort of documentation of the analysis package of Jinq? – Eyad Sep 25 '14 at 06:00
  • If you're only doing simple queries though, it'll be a lot easier just to design a simpler API that doesn't require lambdas as input. If you have a specific question about Jinq, it's probably easier just to e-mail me directly about it. There is no documentation for the analysis package. You can see how it is used by looking at the jinq-jpa/main/org/jinq/jpa/transform/LambdaInfo.java file. – Ming-Yee Iu Sep 26 '14 at 15:55
  • C# does have some great features. Microsoft's design philosophy is to add new features to C# quickly without worrying too much about breaking old things. Java evolves slowly and waits for general consensus before doing so. Experience has shown that Linq expressions are useful for building query systems, as your system is. But are they useful for other things? Why are they limited to expressions? Why not a more powerful metaprogramming feature that also works with statements? This lack of consensus is why Java does not have this feature yet. Java offers annotations as a kludgy alternative. – Ming-Yee Iu Oct 21 '14 at 15:45
  • 3
    Dude, you should calm down a bit. I don't see why you're getting so worked up over something as esoteric as programming language design. I sometimes code in C# myself. When I said C# "moves fast and break things", I meant that as a compliment, but I couldn't elaborate due to character limitations in comments. It's the Silicon Valley way. People regularly praise Apple for deprecating old APIs. The natural result of moving fast is that some stuff breaks. Java evolves slowly, but sometimes that's too slow. C# uses a different set of trade-offs than Java. No language is perfect. Chill out, man. – Ming-Yee Iu Oct 23 '14 at 18:51
4

Something like Jinq?

database.customerStream().where(customer -> customer.getName().equals("Alice"));
isalgueiro
  • 1,973
  • 16
  • 20
2

I explain my approach here http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/

Basically, replay the lambda against a fake object that records the interactions at runtime.

benjiweber
  • 416
  • 4
  • 3