astah-info

JPA Code Generation
Tutorial

How to create source code of Entity classes for
JPA (Java Persistence API) 2.x from UML model
JPA & UML

JPA is a Java EE standard O/R(Object-relational) mapping framework for mapping the POJO(Plain old Java object) and relational database and has been considered as a technology that works well with Domain-driven design.

Traditionally the data-oriented approach involves with ER models, so when you use JPA, you would probably use tools like Dali Java Persistence Tools of Eclipse WTP's or Hibernate Tools of JBoss Tools to generate Entity classes by reversing the physical DB scheme. However I find that those reversed classes are less flexible as they are tied with restrictions of its related models such as the  expressions in many-to-many relationships..etc.

On the other hand, UML is often used in the Domain-driven design practice for designing domain models. Using JPA entity models whose expressions are closer to UML, makes it easier to maintain the implementations of domains close as the original Entity models.
In this way, you can also add annotations to Entity classes and customize DDL which JPA generates for mapping physical DB scheme in detailed level.

In this tutorial, I'd like to introduce my approach to generate initial JPA Entity Classes from UML model to develop them.

Generate Code from UML Model

In this tutorial, I will use Astah Professional for creating UML diagram and any<code/> for code generation.
Astah Professional is a software design tool which supports UML 2.x diagrams and ER Diagram by Change Vision and any<code/> is a plug-in developed by Jose Carreno to generate various programming languages like Java, JPA, PHP, C#, Objective-C..etc from UML Class diagrams using templates.

Sample UML Model

Let's use this sample purchase order system model as an example.
  • Customer has a name, and the name is used to identify the Entities
  • PurchaseOrder is related to the Customer with "orderedBy" and  "deliverTo"
  • PurchaseOrder aggregates multiple Items
Picture

Get Templates ready for Code Generation

To generate source code using any<code/>, you need to create template files first and this is the most important step in this tutorial.
Create these two template files and save them in a new folder.
JPA-ENTITY-name.mda
${targetDir}/${c.getFullyQualifiedName("/")}.java
JPA-ENTITY-content.mda
<%  if(c.hasStereotype("entity")) { %>
package ${c.owner.getFullyQualifiedName(".")};

@javax.persistence.Entity
${jpa.classifierSignature(c)} {
	${jpa.primaryKey(c)}

	<%  def atts = c.attributes.findAll({it.name && !jpa.isIdentifier(it)}) %>
	<%  atts.each() { %>
			${jpa.attribute(it)}
	<%  } %>

	<%  atts.each() { %>
			${jpa.getter(it)}
			${jpa.setter(it)}
	<%  } %>
   	
}
<%  } %>

Specify conditions to generate code for

In the "JPA-ENTITY-content.mda" file, we specify to generate code of classes only if they have "entity" stereotypes.
By specifying this condition, you can model JPA classes and other classes all together in one same project without worrying about generating unnecessary codes..etc.

Generate primary keys

The jpa.primaryKey() method detects primary keys from each class and generates a field, getter and setter. It detects primary keys following the guideline below:
  • For a class which doesn't have any attributes with "id" stereotype, a primary key(Long) will be generated by default
  • For a class which has a single "id" stereotyped attribute, an unique primary key will be generated based on it
  • For a class which has multiple attributes with "id" stereotypes, it will look into its PK class. (We need to make a template for this but we are skipping this in this tutorial.)

Attributes and relationships

By using the Groovy findAll() which takes closure, it can loop the persistent classes and relationships to the JPA Entities. Navigable or unspecified-navigability associations will be included in attributes, so that annotations will be added accordingly and automatically by default.

Navigability is very important to indicate to JPA that the association is either one way or both ways, also it is used to identify the ownership of the relationship, in the one-to-one, one-to-many or many-to-many relationships. A is the owner of all the cases below:

  • A x-> B
  • A -> B
  • A x- B


In this sample model, "PurchaseOrder" owns "Item", so the appropriate "mappedBy" option will be included in the generated source code.

Generated Source Code

Since I used simple default methods for exporting fields, getters and setters such as the jpa.attribute()...etc, the exported code is very simple (You can see the source code at the end of this tutorial). However there are abundant ways you can do with this any<code/>, for example when a property is added to an association, you can make the the other side of association to update with this change automatically by creating a template to do so.

Summary

Hope this tutorial helps you understand how you can generate initial JPA Entity classes code from UML models to develop with.

  • Entity classes created by reversing from database are NOT flexible in its expression as they are tied with related models restrictions
  • Using Entity classes generated by UML models makes it easier to maintain the implementations close to the original entity models

So how about you try this out if you prefer to have higher expressions in the Entity models. (Download is available under [Try].)

To see what more you can do with this any<code/> such as JPA directives, how to create Repository Interface for Spring Data.. etc, please refer to the any<code/> website and tutorials.

At last, we'd like to send a big thank-you to Mr. Jose Carreno for creating such significant plug-in.

Try

Download Astah for free and try go through this tutorial by yourself.
Download Astah Professional
画像
Download Sample Class Diagram
画像
Tutorial Video

Appendix : Exported Source code through this tutorial

PurchaseOrder.java
package com.example.po;

@javax.persistence.Entity
public class PurchaseOrder {
    @javax.persistence.Id
    private java.lang.Long id;

    public final java.lang.Long getId() {
        return this.id;
    }

    public final void setId(final java.lang.Long someId) {
        this.id = someId;
    }

    @javax.persistence.OneToMany(mappedBy = "purchaseOrder")
    private java.util.List items;

    @javax.persistence.ManyToOne
    private Customer orderedBy;

    @javax.persistence.ManyToOne
    private Customer deliverTo;

    public final java.util.List getItems() {
        return this.items;
    }

    public final void setItems(final java.util.List someItems) {
        this.items = someItems;
    }

    public final Customer getOrderedBy() {
        return this.orderedBy;
    }

    public final void setOrderedBy(final Customer someOrderedBy) {
        this.orderedBy = someOrderedBy;
    }

    public final Customer getDeliverTo() {
        return this.deliverTo;
    }

    public final void setDeliverTo(final Customer someDeliverTo) {
        this.deliverTo = someDeliverTo;
    }

}
Item.java
package com.example.po;

@javax.persistence.Entity
public class Item {
    @javax.persistence.Id
    private java.lang.Long id;

    public final java.lang.Long getId() {
        return this.id;
    }

    public final void setId(final java.lang.Long someId) {
        this.id = someId;
    }

    private String product;

    private int quantity;

    private double price;

    @javax.persistence.ManyToOne
    private PurchaseOrder purchaseOrder;

    public final String getProduct() {
        return this.product;
    }

    public final void setProduct(final String someProduct) {
        this.product = someProduct;
    }

    public final int getQuantity() {
        return this.quantity;
    }

    public final void setQuantity(final int someQuantity) {
        this.quantity = someQuantity;
    }

    public final double getPrice() {
        return this.price;
    }

    public final void setPrice(final double somePrice) {
        this.price = somePrice;
    }

    public final PurchaseOrder getPurchaseOrder() {
        return this.purchaseOrder;
    }

    public final void setPurchaseOrder(final PurchaseOrder somePurchaseOrder) {
        this.purchaseOrder = somePurchaseOrder;
    }

}
Customer.java
package com.example.po;

@javax.persistence.Entity
public class Customer {
    @javax.persistence.Id
    private String name;

    public final String getName() {
        return this.name;
    }

    public final void setName(final String someName) {
        this.name = someName;
    }

    private String address;

    private String phoneNumber;

    private String email;

    public final String getAddress() {
        return this.address;
    }

    public final void setAddress(final String someAddress) {
        this.address = someAddress;
    }

    public final String getPhoneNumber() {
        return this.phoneNumber;
    }

    public final void setPhoneNumber(final String somePhoneNumber) {
        this.phoneNumber = somePhoneNumber;
    }

    public final String getEmail() {
        return this.email;
    }

    public final void setEmail(final String someEmail) {
        this.email = someEmail;
    }

}

製品

astah* professional
astah* SysML
astah* GSN
astah* UML
astah* community
astah* share
astah* think!
astah* UML Pad
エディション比較

価格・購入

ライセンスと価格
ライセンス比較表
購入する
購入に関するFAQ

FAQ

astah* professional
astah* SysML
astah* GSN
astah* UML
astah* community
astah* share
astah* think!
astah* ファカルティ
セミナ/CVメンバーズ

ラーニング

チュートリアル
動画チュートリアル
UML初学者向けチュートリアル
ショートカットキー
プラグイン (無償)
astah* API
TIPS集
オンラインマニュアル
​ユーザーコミュニティ

© COPYRIGHT 2009-2018.
​Change VIsion, Inc.  ALL RIGHTS RESERVED.