What’s new in simple-jpa 0.5?


simple-jpa 0.5 has been released.   This release includes new features and important refactoring, which some are not compatible with previous releases.   It is not recommended to upgrade your existing project with previous releases to 0.5.

What is simple-jpa?   It is a plugin for Griffon.  Why do I need simple-jpa?   Here is the history…

When I was working in a Spring web based application, I learned about Spring Data Repositories.   The documentation says “the goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.”   I was so excited at that time.   JPA entities instantly have their own CRUD functionality.   It feels so right:  I should focus on writing business logic (the problem domain) rather than tackling with database access or writing AJAX code in view.   Later I learned that Spring Data Repositories was inspired from Grails dynamic finders.   I tried to follow tutorials on Grails.   It is cool, but I have to learn a new language called Groovy.   There is also Spring Roo, a Grails-like convention-over-configuration tool and it is Java-based.   I haven’t decided which one is better for me when some people asked me to develop desktop business application.   Writing a simple game or graphical application using Java 2D is easy, but business application is a different animal.   I feel that Java is not agile enough.   I need MVC, dependency injection, dynamic finders and other features to speed up development and reduce complexity.   Then I found Griffon.   It uses Groovy’s Swing Builder in its view so designing views is very easy even without visual editor.   Griffon also introduces MVCGroup to group model, view, and controller in one place and make them available to each other.   I then invested my time in learning Groovy and Griffon.

Although Griffon is advertised as Grails’ cousin, some Grails features such as dynamic finders and scaffolding are not yet implemented in Griffon.   I feel that those features will increase agility in building desktop business applications.   That is why I started simple-jpa development.    Its main purpose is to make Griffon as comfortable as possible for developing desktop business-oriented application.   I’ve a limited resource so I started with developing very simple finders and primitive scaffolding to aid me in my own projects.   Of course they are not as powerful as Grails’ GORM.

I don’t use dynamic finders everywhere.   Dynamic finders are useful for simple query but for more complex query, I prefer to use named query.   Because named queries are precompiled, they have better performance.   I can call a named query in simple-jpa 0.5 by using executeNamedQuery () method.   In some cases, I need to search for entities based on one or more conditions.   For example, in a typical search screen, user is usually presented with one or more search criteria.   I don’t know what query to execute in advance, so I can’t use dynamic finders.   In this case, I can use findDomainClassByDsl() which accept a closure with query-like Dsl support.   By using if statements inside this Dsl closure, I can easily build query based on certain conditions.

Despite simple-jpa has JPA as part of its name, it has been depending on Hibernate JPA provider.   I changed this in simple-jpa 0.5.   Now, it doesn’t include particular JPA provider, Bean Validation implementation and JDBC driver.   Plugin user can change default dependencies by editing build configuration file in project.   But I don’t believe I could rely on JPA in production.   I often find myself using provider specific features that are not found in JPA.   For example, in most cases, I use Hibernate @Type for persisting Joda-Time types.   JPA doesn’t support custom data types aside from @Embeddable entities.

After several attempts to create Griffon’s view,   I found out that table binding is best used with Glazed Lists.   Groovy built-in table nodes are not designed with Glazed Lists in mind.   That is why simple-jpa includes additional SwingBuilder nodes for working with Glazed Lists.   Although Griffon’s view with simple-jpa nodes is simpler than plain Java Swing code, I’ve noticed views in my projects have grown more complicated in production.   For that reason, I included new nodes for rendering table (such as glazedTable and glazedColumn) in simple-jpa 0.5.

Don’t forget to visit simple-jpa 0.5 documentation in http://jockihendry.github.io/simple-jpa/v0.5.html for more information.   It contains the details of all simple-jpa 0.5 features.

Perihal Solid Snake
I'm nothing...

4 Responses to What’s new in simple-jpa 0.5?

  1. Komang Hendra Santosa mengatakan:

    mas kok ga bs buat simple-jpa ya pake yg versi ini muncul error seperti ini, klo ga salah di driver mysqlnya deh mas..

    java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost
    at java.sql.DriverManager.getConnection(DriverManager.java:604)
    at java.sql.DriverManager.getConnection(DriverManager.java:221)
    at java_sql_DriverManager$getConnection.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSi
    teArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:124)
    at _GriffonSettings$_run_closure1.doCall(_GriffonSettings:159)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
    90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1076)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)

        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
        at groovy.lang.DelegatingMetaClass.invokeMethod(DelegatingMetaClass.java
    

    :149)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at groovy.lang.Closure.call(Closure.java:412)
    at groovy.lang.Closure.call(Closure.java:425)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
    90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1076)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)

        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
        at groovy.lang.DelegatingMetaClass.invokeMethod(DelegatingMetaClass.java
    

    :149)
    at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaC
    lassSite.java:39)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSi
    teArray.java:45)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaC
    lassSite.java:54)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:116)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure
    16_closure18.doCall(GantBinding.groovy:184)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure
    16_closure18.doCall(GantBinding.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMet
    hodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:272)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMeta
    MethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:112)
    at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:89)
    at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groo
    vy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
    90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1076)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)

        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1021)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)
    
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:727)
        at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java
    

    :44)
    at groovy.lang.MetaClassImpl.invokeMethodOnGroovyObject(MetaClassImpl.ja
    va:1141)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1035)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)

        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(Po
    

    goMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
    tractCallSite.java:149)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure
    16.doCall(GantBinding.groovy:184)
    at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure
    16.doCall(GantBinding.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMet
    hodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:272)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMeta
    MethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:112)
    at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMet
    hodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:272)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMeta
    MethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSi
    teArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:116)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMet
    hodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:272)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMeta
    MethodSite.java:64)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSi
    teArray.java:45)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMeta
    MethodSite.java:69)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
    llSite.java:112)
    at gant.Gant.withBuildListeners(Gant.groovy:427)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent
    (CallSiteArray.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
    tractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(Abs
    tractCallSite.java:141)
    at gant.Gant.dispatch(Gant.groovy:415)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
    90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1076)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1106)

    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:906)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:729)
    at gant.Gant.invokeMethod(Gant.groovy)
    at groovy.lang.GroovyObject$invokeMethod.callCurrent(Unknown Source)
    at gant.Gant.executeTargets(Gant.groovy:591)
    at gant.Gant.executeTargets(Gant.groovy:590)
    at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstance(
    GriffonScriptRunner.java:648)
    at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstanceN
    oException(GriffonScriptRunner.java:667)
    at org.codehaus.griffon.cli.GriffonScriptRunner.callPluginOrGriffonScrip
    t(GriffonScriptRunner.java:392)
    at org.codehaus.griffon.cli.GriffonScriptRunner.doExecuteCommand(Griffon
    ScriptRunner.java:303)
    at org.codehaus.griffon.cli.GriffonScriptRunner.main(GriffonScriptRunner
    .java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.griffon.cli.support.GriffonStarter.rootLoader(GriffonSta
    rter.java:198)
    at org.codehaus.griffon.cli.support.GriffonStarter.main(GriffonStarter.j
    ava:223)

    Can’t create new database! No suitable driver found for jdbc:mysql://localhost

    at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstance(
    

    GriffonScriptRunner.java:648)
    at org.codehaus.griffon.cli.GriffonScriptRunner.executeWithGantInstanceN
    oException(GriffonScriptRunner.java:667)
    at org.codehaus.griffon.cli.GriffonScriptRunner.callPluginOrGriffonScrip
    t(GriffonScriptRunner.java:392)
    at org.codehaus.griffon.cli.GriffonScriptRunner.doExecuteCommand(Griffon
    ScriptRunner.java:303)
    at org.codehaus.griffon.cli.GriffonScriptRunner.main(GriffonScriptRunner
    .java:141)
    at org.codehaus.griffon.cli.support.GriffonStarter.rootLoader(GriffonSta
    rter.java:198)
    at org.codehaus.griffon.cli.support.GriffonStarter.main(GriffonStarter.j
    ava:223)
    Caused by: : Can’t create new database! No suitable driver found for jdbc:mysql:
    //localhost
    at org.apache.tools.ant.taskdefs.Exit.execute(Exit.java:164)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.jav
    a:106)
    at _GriffonSettings$_run_closure1.doCall(_GriffonSettings:201)
    … 7 more

    • Solid Snake mengatakan:

      Terima kasih atas laporannya. Ini adalah efek samping dari perubahan di v0.5 dimana agar tidak terikat pada satu database, simple-jpa tidak lagi menyertakan driver JDBC MySQL. Bug di atas timbul karena driver JDBC tidak ada di proyek sehingga perintah create-simple-jpa tidak dapat membuat database baru. Saya akan segera memperbaiki bug ini.

      Untuk sementara, salah satu alternatif adalah dengan menambahkan -skipDatabase seperti pada perintah berikut ini:

      griffon create-simple-jpa -user=xxx -password=xxx -database=xxx -skipDatabase
      
  2. Solid Snake mengatakan:

    Bug di atas sudah diperbaiki di simple-jpa 0.5.2. Kini, perintah create-simple-jpa akan men-download JDBC driver yang dibutuhkan. Selain itu, juga ada tambahan dukungan database Apache Derby embedded. Untuk menggunakannya, tambahkan -jdbc=derby-embedded. Nilai default adalah -jdbc=mysql.

    Baca https://thesolidsnake.wordpress.com/2013/12/14/whats-new-in-simple-jpa-0-5-2/ untuk informasi lebih lanjut.

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: