agentgt / jirm

A Java Immutable object Relational Mapper focused on simplicity, convenience, and thread safety.
Apache License 2.0
66 stars 10 forks source link

Strongly-typed Fluent API? #3

Open mstine opened 11 years ago

mstine commented 11 years ago

Hi! I'm currently working on a new talk for the 2013 No Fluff Just Stuff tour entitled "Programming with Immutability." I was very pleased to find JIRM, as one of the primary questions that I get when I discuss immutability on the tour is "How do I do Hibernate with immutable classes?"

I really like your fluent API. I'm wondering what it would take to make it strongly-typed?

For example...the following code:

customerService.getDao().update()
   .set("name", "John Doe")
   .where().property("id", 1L)
   .execute();

might become:

customerService.getDao().update()
   .set(name(), "John Doe")
   .where().property(id(), 1L)
   .execute();

or something similar. Since we know the type of the class that the Dao is for, it seems like this should be possible. I'd be interested in helping with this if you could point me to the right place to start looking at it.

Thanks again! -Matt

lukaseder commented 11 years ago

(Disclaimer: I'm not the repo owner, I'm just following this project) I feel that Lambdaj might have a good answer to this problem: http://code.google.com/p/lambdaj/

Lambdaj allows for expressing property proxies like this:

// Bean proxy 
on(Person.class);

// Property proxy
on(Person.class).getAge()

More details: http://lambdaj.googlecode.com/svn/trunk/html/apidocs/ch/lambdaj/Lambda.html#on(java.lang.Class)

Translated to your example, this could become something along these lines:

JirmDao<CustomerBean> dao = customerService.getDao();
dao.update()
   .set(dao.bean().name(), "John Doe")
   .where().property(dao.bean().id(), 1L)
   .execute();

Where dao.bean() would wrap the bean proxy, and dao.bean().name() would be a property proxy. If this works out, I might start stealing more ideas from JIRM ;-)

mstine commented 11 years ago

Yes! I very much has Lambdaj in mind when I wrote this...just didn't get the syntax quite right.

I may try this in a local branch and see how it goes.

Sent from my iPhone

On Jan 12, 2013, at 4:32 PM, Lukas Eder notifications@github.com wrote:

(Disclaimer: I'm not the repo owner, I'm just following this project) I feel that Lambdaj might have a good answer to this problem: http://code.google.com/p/lambdaj/

Lambdaj allows for expressing property proxies like this:

// Bean proxy on(Person.class);

// Property proxy on(Person.class).getAge() More details: http://lambdaj.googlecode.com/svn/trunk/html/apidocs/ch/lambdaj/Lambda.html#on(java.lang.Class)

Translated to your example, this could become something along these lines:

JirmDao dao = customerService.getDao(); dao.update() .set(dao.bean().name(), "John Doe") .where().property(dao.bean().id(), 1L) .execute(); Where dao.bean() would wrap the bean proxy, and dao.bean().name() would be a property proxy. If this works out, I might start stealing more ideas from JIRM ;-)

— Reply to this email directly or view it on GitHub.

agentgt commented 11 years ago

I thought about doing this Matt but some of the reasons I did not are:

You should definitely checkout @lukaseder (Lukas Eder) JOOQ library (he humbly omitted that in his previous comment :) ) as it supports querying into immutable POJOs with a fluent API. JOOQ is more database table focus and I guess mine is more immutable object focused. Actually sort of funny thing is we have sister projects in both database (JOOQ, JIRM) and (X)HTML generation (JOOX, JATL). I will say his are generally superior and I really should have started reading his blog lot sooner to avoid duplication :) .

That being said I think I can see how I can do this as I have seen it done with things like Mockito and jMock (both use state machines and dynamic proxies IIRC).

agentgt commented 11 years ago

Matt (@mstine), I was thinking about this last night again and remembered why I didn't explore this more. I think the real issue is that Java Bean's or I should say Java Properties are "made up" citizens in the Java language. (Lukas just blogged about this).

The problem is that is impossible in Java to statically refer to a property. However there are code generators that will take some sort of description and generate an immutable object with static references to all its properties (ie meta-data). One example is Protobuf.

So what I'm proposing instead of the dynamic proxy approach which requires tricky state management and object bytecode generation, and is potentially slow, is that we could just generate immutable objects with their metadata (field names and types as static constants) with a code generator. The jOOQ project code generates based on SQL tables. Perhaps JIRM should approach it from the reverse: Generate based on Immutable Struct definitions (ala protobuf).

Some people see code generation as evil but I don't think its so bad as long as its seamlessly integrated into the toolchain. JSR 269 is one option to explore (see genftw). Another option is to explore an Eclipse Code generator (which is infact what I do right now with a custom version of bpep), or come up with another description language like protobuf.

Finally (and sorry for the lack of brevity but I know your looking for content for NFJS) you might want to check out some hacks I did to make Spring MVC databinding work with immutable objects on stackoverflow. With the Spring hack and JIRM I have almost eliminated regular getter/setter Java beans in my newer projects.

mstine commented 11 years ago

Thanks folks for all of the feedback/ideas.

This is definitely not a deal breaker for me. I'll certainly be highlighting JIRM in my talk. I was able to get a basic "Hello World" app bootstrapped fairly easily. The strong-typing would be a nice addition, as I feel like it fits in well with the overall spirit of functional programming. While my talk isn't strictly about FP, but rather immutability, I will be mentioning quite a few FP concepts during the discussion.

I'd love to continue thinking/collaborating on this issue. As soon as I get a chance to dig into the code more deeply, I'll consider your points a little more closely.

One quick note: I did notice that when I configured an embedded DB using the Spring JDBC XML namespace, the HSQL metadata seemed to always come back upcased (i.e. "ID" instead of "id")...because of this, I was forced to annotate all of my fields with @Column('COLUMN_NAME') for JIRM to work. Is this an artifact of how JIRM works? Or HSQL? Thanks!

agentgt commented 11 years ago

I will be adding HSQL as to the testing suite very soon so I'll see if I see what your talking about. Right now we only test Postgresql and Mysql.