BestPracticesWithJPAAndBeansBinding

Best Practices with JPA and Beans Binding

by Jan Stola.

NetBeans GUI builder (since NB 6.0 release) provides support for JSR 295 Beans Binding. Synchronization of the application's data model with the information displayed in UI components is usually a daunting task when coding a new GUI. Beans Binding simplifies this process by providing an easy way to connect two properties. Hence if your data model

is based on JavaBeans specification, e.g. if it has
get
<Attribute> and
set
<Attribute> methods for all its important attributes,

then it is simple to use NetBeans binding support to bind your model to Swing components. You may argue that many Swing components are not beans with nice attributes/properties

(for example the model property of
JTable
is quite complex),

but you don't need to worry about that. Beans Binding improves the behaviour of some Swing components (e.g. adds property change

notification when text of
JTextComponent
is modified) and

adds few handy artificial properties where standard components

lack them - like elements property of
JTable
that allows you

to set the table model in terms of collection of JavaBeans.

Image:bindingProperties_BestPracticesWithJPAAndBeansBinding.jpg

The data processed by the application are stored in a relational database frequently. So, you need to load the data somehow and create bean wrappers to be able to use beans binding. Java Persistence API (JPA) is ideal for this purpose. JPA is a standard object-relational mapping for Java e.g. it is a technology that does exactly what we need, it maps Java objects to corresponding data in the database. JPA started in, but is not specific to J2EE world. There are already several implementations available for standalone applications as well. The NetBeans distribution includes one of them: TopLink - JPA implementation by Oracle.

Image:newJDAApplication_BestPracticesWithJPAAndBeansBinding.jpg

Image:newDBShell_BestPracticesWithJPAAndBeansBinding.jpg

Image:masterTable_BestPracticesWithJPAAndBeansBinding.jpg

Image:detailTable_BestPracticesWithJPAAndBeansBinding.jpg

The easiest way to start with NetBeans beans/data binding support is to create a Java Desktop Application/Database Application Shell. You can find it in the New Project ... wizard. This wizard creates a skeleton of simple CRUD (create, read, update and delete) database application with master/detail view. In the sequel we assume that we have an application

called CustomerApp created from
CUSTOMER
master table and {PURCHASE_ORDER}

detail table.

Image:runningApp_BestPracticesWithJPAAndBeansBinding.jpg

Let's examine the generated application. The most important

class is
CustomerView
that contains the GUI of the application's main window. If you select the
detailTable
then you can

see the properties of this table in Properties window. The Binding section of this window contains information about bound properties.

You can, for example, see that the
elements
property of
detailTable
is bound to {${selectedElement.purchaseOrderCollection} } expression of masterTable. The binding source (e.g.
masterTable
in this case)

represents a context in which the binding expression is evaluated whenever sychronization is required (for example when selection in the masterTable changes). The binding expressions are usually

simple properties (
${foreground
}) or property paths ({${selectedElement.address.street}}),

but they can be arbitrary EL expressions known from JSP

(
${firstName} ${lastName} 
or {${selectedElement != null}}).

The Advanced tab of the binding customizer allows you to affect additional binding aspects: coverter (when the types of bound properties do not match), validator (to avoid corruption of the source of the data) etc.

Image:bindingCustomizer1_BestPracticesWithJPAAndBeansBinding.jpg

Besides the main view (CustomerView.java), about dialog (CustomerAboutBox.java) and the application main class (CustomerApp.java) the project contains two data access classes (called entities): Customer.java and PurchaseOrder.java. The annotations in these classes help JPA to map the data from DB tables and columns to the corresponding entities and fields/properties in the entities.

Image:entity_BestPracticesWithJPAAndBeansBinding.jpg

The entities for our application were generated when the project was created, but you can generate additional entities for other DB tables using Entity Classes from Database wizard (accessible through Persistence category of New File dialog).

Image:entityClassesFromDB_BestPracticesWithJPAAndBeansBinding.jpg

If the DB tables that we would like to access have some foreign keys e.g. if the corresponding entities have some relations (many-one, one-many etc.) then it is important to generate all the entities together to make sure these relations are correctly expressed in generated classes. For example, if you generate PurchaseOrder entity without Customer entity then

the
customerId
field that represents the relation between these entities

will have type int (instead of Customer) or will not be generated at all.

When the entity classes are used with beans binding then it is necessary to add property change support into them. Firstly, the entity should

have
addPropertyChangeListener()
and {removePropertyChangeListener()}

methods for (un)-registration of property change listeners. Secondly, every setter

(
set
<Property>{()} method) should notify all registered listeners

about the preformed change. The GUI builder attempts to add this support for you whenever it is needed, but you should not depend on it. It is sometimes not possible to determine that automatically. Therefore double check your property change support whenever you encounter a problem in sychronization done by beans binding.

Image:changeSupport_BestPracticesWithJPAAndBeansBinding.jpg

By default, it is necessary to set (value of) field/property that correspond to the primary key before the data can be stored into the database. This may be fine if your primary key makes sense in real world (e.g. it is a social number of the customer), but it is annoying if the key should be just a unique number (possibly generated from some sequence). If your DB provides this support then you can utilize it in your entities as well. It is sufficient

to add something like
@GeneratedValue(strategy=GenerationType.IDENTITY)
just below
@Id
annotation next to your primary key.

Image:generatedId_BestPracticesWithJPAAndBeansBinding.jpg

Embedded Database

Usually the application's database is located on some DB server that is accessible over network, but there are some cases when it is preferable to have the DB locally for each installation of the application - for example when the application manages the set of your music records or books. It is ideal to use embedded DB in this case. You can use for example free lightweight embedded DB provided by Derby/Java DB. The usage of this DB is similar to the usage of network DBs. You just have to

use
org.apache.derby.jdbc.EmbeddedDriver
instead of {ClientDriver}.

Of course, you don't need to specify hostname and port in DB

url. It is sufficient to include the DB name e.g.
jdbc:derby:mydb
. Derby will look for DB called
mydb
in a working directory.

Image:newConnection_BestPracticesWithJPAAndBeansBinding.jpg

If you want to create the DB in case it doesn't exist already (for example, during the first start after installation) then you can do that by setting create parameter

in DB URL to true e.g.
jdbc:derby:mydb;create=true

Don't be confused if you don't see the data (or even tables) when you run your application in spite of the fact that you can see them in Services window of NetBeans. Recall that Derby is looking for the DB in the working directory and the working directory of NetBeans is different from the working directory of your project.

The create parameter ensures creation of the DB only. It doesn't help you with the creation of DB tables. Hapilly, you can utilize one nice feature of JPA. JPA is able to create missing DB tables that correspond to entity classes in your application. Open persistence.xml file in META-INF directory of your project. This file contains configuration data used by your JPA provider. If you change Table Generation Strategy to Create then missing DB tables will be created automatically for you.

Image:createTables_BestPracticesWithJPAAndBeansBinding.jpg

Do not forget that Embedded DB requires the whole DB engine on the classpath. So, it is not sufficient to use derbyclient.jar that contains the driver only, you have to use derby.jar.

FAQs

Finally, I would like to mention few FAQs whose answers didn't make it into the above text:

How to specify an additional binding source?

The binding source combo box in the binding customizer offers the list of components added into the form (e.g. the components that you can see in Inspector window). Sometimes it is necessary to specify another binding source, for example your application model that is not added directly into your form. In this case,

it is the best to add a getter for this object e.g.
getModel()
into the form class. After that you can use
Form
as the binding source and
${model.yourOriginalExpression} 
as the binding expression.

Why do my bound list/table/combo box is not updated when I add a new object into the corresponding list?

Standard JDK collections are not observable e.g. it is not possible to by notified about their changes. Fortunately, Beans Binding provides a set of observable collections that can be used as wrappers. Hence if you encounter the described problem then make sure

that you wrap your list using
ObservableCollections.observableList(originalList)
.

Even when you use this wrapper you must ensure that you don't

modify it directly using methods of the underlying
originalList
.

You must add/remove elements through methods of the wrapper only (to allow the list to generate correct events).

Why do my entities show old values?

It might be due to TopLink's session cache. I will not delve

into technical details, but it may help to call
refresh()

on your entity. If you find this annoying then you can

try to set
toplink.cache.shared.default
property to {false} in
persistence.xml
. See http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t.html

for details.

How can I bind Date objects to some UI component easily?

Use JFormattedTextField and its value (not text!) property.

Finally use property editor for
formatterFactory
property

(of the formatted field) to customize the date/time format.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo