What’s new in simple-jpa 0.4.1


simple-jpa 0.4.1 is a bug fix release.  It fixes several major bugs which cause data inconsistencies.   There are also several new features included here.   More information can be found in simple-jpa’s release notes (http://artifacts.griffon-framework.org/package/plugin/simple-jpa/0.4.1).

In the previous release, simple-jpa only exposes the following EntityManager’s methods: persist(), merge() and remove(). To call other methods such as refresh(), clear(), detach(), or lock() (the complete reference is in http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html), I must write code like this:

getEntityManager().refresh(entity) // call EntityManager’s refresh()

In simple-jpa 0.4.1, all of EntityManager’s methods are exposed, so the following code is doing the same thing as previous one:

refresh(entity) // call EntityManager’s refresh()

If there is a method defined with the same name, then the declared method will be called instead. For example, the following code will not call EntityManager’s refresh():

def refresh = {
   ...
}

def test = {
   ...
   refresh(entity) // call refresh closure in the above
   getEntityManager().refresh(entity) // call EntityManager’s refresh()
}

The other new feature is scaffolding generator will generate enumeration type as combo box with predefined value. For example, this is domain class with JPA @Enumerated attribute:

enum Gender { MALE, FEMALE }

@DomainModel @Entity @Canonical
class MyEntity {

   @NotNull @Enumerated
   Gender gender

}

Based on the domain class above, simple-jpa 0.4.1 will generate the following view:

Generated view with enumerated attribute

Generated view with enumerated attribute

This is useful for generating attributes with value that will never change (for example, gender always consists of male and female).

simple-jpa 0.4.1 also introduces tableColumnConfig node that can be used inside table node. While eventTableModel node can be used to configure data for table based on GlazedLists’ TableFormat, it can’t be used to configure view related attributes (for example, cell renderer and header renderer). By default, table column, cell and header renderer are created automatically based on table’s model. tableColumnConfig node will not create new renderer; it will change the attribute of existing renderers instead. That is why it must be used after eventTableModel definition.

tableColumnConfig uses a numeric key to indicate which column to configure (column number start from zero). The configuration itself is in the form of Map whose key is a property/attribute of TableColumn (see http://docs.oracle.com/javase/7/docs/api/javax/swing/table/TableColumn.html) and value is the new content of that property. For example, the following code will set the size of the second column (index 1) and make it can’t be resized:

table(rowSelectionAllowed: true, id: 'table') {
   eventTableModel(list: model.myEntityList,
       columnNames: ['Attribute1', 'Attribute2', 'Attribute3'],
       columnValues: ['${value.attribute1}', '${value.attribute2}', '${value.attribute3}'])
   tableColumnConfig(
       1: ['maxWidth': 50, 'resizable': false]
   )
   table.selectionModel = model.myEntitySelection
}
Using tableColumnConfig for configuring table's column width

Using tableColumnConfig for configuring table’s column width

To refer the cell renderer for current column, I need to use “cellRenderer”. Because default cell renderer is a JLabel, it will usually followed by a JLabel’s property. For example “cellrenderer.background” will configure cell renderer background, as shown in the code below:

table(rowSelectionAllowed: true, id: 'table') {
   eventTableModel(list: model.myEntityList,
       columnNames: ['Attribute1', 'Attribute2', 'Attribute3'],
       columnValues: ['${value.attribute1}', '${value.attribute2}', '${value.attribute3}'])
   tableColumnConfig(
       1: ['maxWidth': 50, 'resizable': false],
       2: ['cellRenderer.background': Color.LIGHT_GRAY]
   )
   table.selectionModel = model.myEntitySelection
}
Using tableColumnConfig for configuring table's cell renderer

Using tableColumnConfig for configuring table’s cell renderer

The following code will right align the third column:

table(rowSelectionAllowed: true, id: 'table') {
    eventTableModel(list: model.myEntityList,
        columnNames: ['Attribute1', 'Attribute2', 'Attribute3'],
        columnValues: ['${value.attribute1}', '${value.attribute2}', '${value.attribute3}'])
    tableColumnConfig(
        1: ['maxWidth': 50, 'resizable': false],
        2: ['cellRenderer.background': Color.LIGHT_GRAY,
            'cellRenderer.horizontalAlignment': SwingConstants.RIGHT]
    )
    table.selectionModel = model.myEntitySelection
}
Using tableColumnConfig to right align a column

Using tableColumnConfig to right align a column

Note that content of the column is right aligned, but it is not the case with the column header. To configure header renderer, I need to use ‘headererRenderer’. Because JTable will reuse the same header renderer, all column headers must be configured to get a consistent result, as shown in the following code:

table(rowSelectionAllowed: true, id: 'table') {
   eventTableModel(list: model.myEntityList,
      columnNames: ['Attribute1', 'Attribute2', 'Attribute3'],
      columnValues: ['${value.attribute1}', '${value.attribute2}', '${value.attribute3}'])
   tableColumnConfig(
      0: ['headerRenderer.horizontalAlignment': SwingConstants.LEFT],
      1: ['maxWidth': 50, 'resizable': false,
          'headerRenderer.horizontalAlignment': SwingConstants.LEFT],
      2: ['cellRenderer.background': Color.LIGHT_GRAY,
          'cellRenderer.horizontalAlignment': SwingConstants.RIGHT,
          'headerRenderer.horizontalAlignment': SwingConstants.RIGHT]
   )
   table.selectionModel = model.myEntitySelection
}
Using tableColumnConfig to right align table's header

Using tableColumnConfig to right align table’s header

The other new feature is template renderer now can accept closure as argument. This closure must return a String value which will be displayed. Why use a closure instead of template String? For a complex expression (note that it is generally not recommended to have complex expression in renderer), a closure is easier to write and less error prone. The closure can still call helper functions that are used by template renderer such as currencyFormat(), numberFormat(), titleCase(), etc. In the following code, the fourth column renderer is using a closure instead of template String:

table(rowSelectionAllowed: true, id: 'table') {
   eventTableModel(list: model.workOrderEventList,
      columnNames: ['Noticed', 'Occured', 'Event Type', 'Note'],
      columnValues: [
         "\${value.whenNoticed.toString('dd-MM-yyyy hh:mm')}",
         "\${value.whenOccured.toString('dd-MM-yyyy hh:mm')}",
         '${value.eventType}',
         { value ->
            if (value.deleted=='Y') {
               return "Revoked"
            } else if (value instanceof RevokedEvent) {
               return "Revoke Event"
            } else if (value instanceof SparepartSalesEvent) {
               return "${value.sparepart.name} - ${currencyFormat(value.sparepart.price)}"
            }
         } 
      ])
   table.selectionModel = model.workOrderEventSelection
}

Perihal Solid Snake
I'm nothing...

2 Responses to What’s new in simple-jpa 0.4.1

  1. Komang Hendra Santosa mengatakan:

    mas, di simple-jpa 0.4.1 ini bs ga kita pilih multiple item di combobox ya dan nanti distore ke databasenya?

    • Solid Snake mengatakan:

      Memilih “multiple items” identik dengan relasi one-to-many atau many-to-many. Untuk relasi seperti ini, scaffolding generator simple-jpa akan menghasilkan view yang memakai komponen tagChooser() yang memungkinkan memilih lebih dari satu objek.

      Combobox yang berisi checkbox untuk memilih multiple items memang tidak disediakan, tapi kamu dapat membuatnya sendiri. Selama kamu melakukan binding ke data yang sama di model, maka kamu hanya perlu mengubah view (menambahkan komponen buatan sendiri) dan data tetap akan disimpan ke database seperti biasanya.

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: