Sunday Dec 13, 2009

Generating the JPA 2.0 Static MetaModel classes using Eclipselink 2.0 and Netbeans 6.8 for your Entity Classes

Eclipselink 2.0 includes an annotation processor for generating the static metamodel classes from your Entity classes for use with the Criteria API which is one of the new features in JPA 2.0.

Here is an example of generating the metamodel classes from the command line using the Eclipselink annotation processor:


javac -processor org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor -sourcepath src -d src -classpath /ace2_apps/eclipselink/jlib/eclipselink.jar:.:/ace2_apps/eclipselink/jlib/jpa/javax.persistence_2.0.0.v200911271158.jar -proc:only -Aeclipselink.persistencexml=src/META-INF/persistence.xml src/demo/\*.java
Note: Creating the metadata factory ...
Note: Building metadata class for round element: demo.Item
Note: Building metadata class for round element: demo.Order
Note: Found Option : eclipselink.persistencexml, with value: src/META-INF/persistence.xml
Note: File was not found: META-INF/orm.xml
Note: File was not found: META-INF/eclipselink-orm.xml
Note: Found Option : eclipselink.persistencexml, with value: src/META-INF/persistence.xml
Note: File was not found: META-INF/orm.xml
Note: File was not found: META-INF/eclipselink-orm.xml
warning: The following options were not recognized by any processor: '[eclipselink.persistencexml]'


In the above example, the metamodel classes demo.Item_.java and demo.Order_.java were generated and placed in the demo directory where the Entity classes reside.


Netbeans 6.8 has recently been released which provides support for many Java EE 6 features. Unfortunately, there is no support for generating the metamodel classes at this time.


However, it is easy to update your project to provide this support following these steps:


1. Add the following target to your projects build.xml file:

<target name="generate-MetaModel" depends="init">
<property name="metaPackage" value="metamodel"/>
<delete>
<fileset dir="${src.dir}" includes="\*\*/\*_.java"/>
</delete>
<echo message="Generating MetaData "/>
<javac srcdir="${src.dir}" verbose="false"
destdir="${src.dir}"
excludes="demo/\*\*"
classpath="${javac.classpath}">
<compilerarg line=" -processor org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor" />
<compilerarg line=" -proc:only" compiler="javac1.6" />

</javac>

</target>

A couple of notes about the target above:

  • Each time you want to regenerate the metamodel classes, you must delete the previous ones or you will receive an error.
  • The target excludes running the annotation processor against the directory that has the code which references the metamodel classes (demo in the target) otherwise you will see some errors yet the metamodel classes will still be generated.

Once you have added the target to the build.xml, you will want to add a menu option to make it easier to invoke the target. You can do this by:

1. Right clicking on the name of the target and "Create Shortcut"


CreateMenuItem.JPG

2. Indicate that you are adding a "Menu Item"


Wizard1.JPG

3. Select "Refactor" for where to add the Menu Item.


Wizard2.JPG

Now you are ready to use the new target which you can access from the refactor menu:


ShowMenuItem.JPG

The Netbeans project, CriteriaStaticMetaModelDemo, provides a simple set of examples on how to use the Criteria AP. The queries that are provided access the metamodel dynamically and statically as well as demonstrate String based navigation.

The code for using the Static MetaModel example looks like:

private void staticMetaModel() {
System.out.println("\*\*\*Running Static MetaModel Example\*\*\*\*\*");

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<League> cq = cb.createQuery(League.class);
Root<League> league = cq.from(League.class);
cq.select(league);
ParameterExpression<Gender> genderType =
cb.parameter(Gender.class, "gender");

cq.where(cb.equal(league.get(League_.gender), genderType));

TypedQuery<League> tq = em.createQuery(cq);
tq.setParameter(genderType, Gender.Mixed);
List<League> rs = tq.getResultList();
displayLeagues(rs);

CriteriaQuery<String> cq2 = cb.createQuery(String.class);
Root<Team> team = cq2.from(Team.class);
cq2.select(team.get(Team_.name)).where(cb.like(team.get(Team_.name), "Longfellow%"));
TypedQuery tq2 = em.createQuery(cq2);
List<String> teamNames = tq2.getResultList();
displayTeamNames(teamNames);
}


The example creates two queries using the Criteria API. The first query will select all leagues whose gender is equal to "Mixed". Gender is a Enum.

The 2nd query will return all teams whose name begins with "Longfellow".

The static metamodel classes are generated by appending an "_" to the name of the entity. In the example above, League_ and Team_ are the static metamodel classes that were generated for the entities League and Team.

Both queries are quite trivial but show how you can create strongly typed queries using the static metamodel.


For more information on JPA 2.0:

[1] JPA 2.0 Specification

[2]Eclipselink MetaModel Annotation Processor Documentation

[3] CriteriaStaticMetaModelDemo

Thursday Dec 10, 2009

Introducing the DataSourceDefinition Annotation

One of the many cool new features in Java EE 6, is support for the DataSourceDefinition annotation.

The DataSourceDefinition annotation provides a way to define a DataSource and register it with JNDI. The annotation provided annotation elements for the commonly used DataSource properties. Additional standard and vendor specific properties may also be specified.

So let us look at an example:

@DataSourceDefinition(name = "java:global/MyApp/myDS",
className = "org.apache.derby.jdbc.ClientDataSource",
portNumber = 1527,
serverName = "localhost",
databaseName = "testDB",
user = "lance",
password = "secret",
properties = {"createDatabase=create"}) )

The data source will be registered using the value specified in the name element and can be defined in any valid Java EE name space, determining the accessibility of the data source from other components.

The properties element is used to specify less frequently used standard DataSource properties as well as vendor-specified properties using the format :

{"property1=value", "property2=value" ...}

Using the newly defined DataSource is as simple as:

  @Resource(lookup = "java:global/MyApp/myDS")
  private DataSource ds;

You can also define multiple DataSources using the DataSourceDefinitions annotation:

@DataSourceDefinitions({
  @DataSourceDefinition(name = "java:global/MyApp/myDS",
  className = "org.apache.derby.jdbc.ClientDataSource",
  portNumber = 1527,
  serverName = "localhost",
  databaseName = "testDB21",
  user = "lance",
  password = "secret",
  properties = {"createDatabase=create"}),
  @DataSourceDefinition(name = "java:global/MyApp/myDS2",
  className = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource",
  portNumber = 3306,
  serverName = "localhost",
  databaseName = "dogDB",
  user = "luckyDog",
  password = "shhh",
  properties = {"pedantic=true"})
})

So let's look at a simple web application, DataSourceDefWebApp, which utilizes the DataSourceDefinition. The application is provided as a NetBeans project that was created with NetBeans 6.8.

The application when deployed, will create a DataSource for Java DB.

When you go to run the application, you will need to make sure that you have the Java DB client JDBC driver accessible to your appserver, which it will be for Glassfish V3 and the Java DB server started.

To run the application after you have deployed it, go to the following URL using your favorite browser:

http://<host>:<port>/DataSourceDefWebApp

When you first run the application, you will see the following menu. Select the menu option "Initialize the Database", to create the Java DB database and create two initial contacts.

AdminMenu.JPG

After initializing the database you can select "Add a Contact" to add a new contact to your database.

AddContact.JPG

When you click the "Add Contact", button you will be taken to the displayContacts page.

DisplayDerby.JPG ,  

The application defines the DataSource in the DataSourceDefServlet:

@DataSourceDefinition(name = "java:global/MyApp/myDS",
className = "org.apache.derby.jdbc.ClientDataSource",
portNumber = 1527,
serverName = "localhost",
databaseName = "testDB",
user = "lance",
password = "secret",
properties = {"createDatabase=create"})
@WebServlet(name = "DataSourceDefServlet", urlPatterns = {"/DataSourceDefServlet", "/displayContacts", "/addContact", "/initDB"})
public class DataSourceDefServlet extends HttpServlet {private ServletContext context;
@Resource(lookup = "java:global/MyApp/myDS")
private DataSource ds;


The DataSourceDefinition annotation is specified above the class declaration. The Resource annotation is then used specifying the JNDI name that was defined in DataSourceDefinition.

The Stateless Session bean, DemoBean, also uses the Resource annotation to access the same DataSource via:

@Resource(lookup = "java:global/MyApp/myDS")
private DataSource ds;

You can also override the settings that you have specified in the DataSourceDefinition annotation by adding the data-source element to your web.xml. For example, in order to use a MySQL database instead of Java DB, you can create a web.xml and add the following (remember to adjust the properties as necessary):

<data-source>
<description>DataSource for MySQL</description>
<name>java:global/MyApp/myDS</name>
<class-name>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</class-name>
<server-name>localhost</server-name>
<port-number>3306</port-number>
<database-name>testDB</database-name>
<user>lance</user>
<password>secret</password>
<property>
<name>x</name>
<value>y</value>
</property>
<property>
<name>y</name>
<value>x</value>
</property>
<login-timeout>500</login-timeout>
<transactional>false</transactional>
<isolation-level>TRANSACTION_READ_COMMITTED</isolation-level>
<initial-pool-size>2</initial-pool-size>
<max-pool-size>5</max-pool-size>
<min-pool-size>1</min-pool-size>
<max-idle-time>500</max-idle-time>
<max-statements>100</max-statements>
</data-source>

In the top level directory of the DataSourceDefinitionWebApp, you will find a web.xml that you can move to the web/WEB-INF folder of the project. Adjust the properties for the data-source to correctly point to your MySQL database, then rebuild and deploy.

When you go to display the data, you will notice that the the output from displayContacts indicates thatthe database that is being used in MySQL

OverrideWithMysql.JPG

The DataSourceDefinition annotation is a simple yet powerful addition to Java EE 6. Enjoy!


References:


About

user12629431

Search

Categories
Archives
« December 2009 »
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
11
12
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today
Bookmarks