Entities

With entities we mean Entity Beans or EJB3 JPA2 POJOs, i.e. a persistent class like a Company or Person for example. In the EJB3 cartridge you will not need to worry about the underlying persistence technology, but you will probably want to know that EJB3 POJOs will be generated for the entities you model. The EJB 3.0 container (i.e. JBoss) adopts a suitable configurable persistence technology. (i.e Hibernate)

In order to successfully generate a single entity it is sufficient to simply model a single class and assign it the <<Entity>> stereotype, this stereotype tells the EJB3 cartridge to treat this class as an entity.

Let's start by modeling a package org.andromda.test and putting a class inside that package, give that class the name Car. Now make sure that entity has the <<Entity>> stereotype.

images/org/andromda/test/1/a/uml.gif

You can now try to generate code from your model and take a look at what is generated. If you don't know how to generate code using AndroMDA then head on over to the getting started guide (specifically the section explaining how to setup your first AndroMDA project).

If everything went well, all code related to this class will have been generated into the core/target/src project subdirectory, no manual implementation will need to be added at this point.

The EJB3 cartridge changes the conventional entity creation hierarchy. Instead of generating an entity base class with an entity implementation class, there are 2 ways the EJB3 cartridge can generate your entity POJOs.

  • In most cases, your entities will only model classifier scoped finder methods, or a separate controller/query (session bean) class will handle all EJB3 operations for the Entity. If there are no classifier scoped operations, then the cartridge auto generates (and will regenerate) only Entity components for you: the entity POJO and the DAO components associated with the entity. If there are classifier scoped operations, an Embeddable component will be generated, where you will put your operation implementation code. The generated Entity component operations will delegate their implementation to the Embeddable component.
  • The alternative is to have an embeddable/mapped superclass with an entity class that inherits from this mapped superclass. This is the case where the entity models instance scoped operations and are involved in non-inheriting hierarchies. However once you introduce inheritance, the Embeddable Impl class must be maintained. It is only generated once. To find out more about inheritance, go to the inheritance section.
  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

The class we have modeled does not have any properties, however, by default, AndroMDA creates the id attribute of type datatype:Long if no identifier (primary key) attribute has been modeled by the user. It is possible to override these settings in the namespace properties for the AndroMDA maven plugin or the namespace properties for Ant. Click here if you want to know more about the default namespace properties you can set.

Entity Database Table

Your relational table's name which persists an entity is determined by default from the actual entity name. To change the table name assignment in the @javax.persistence.Table annotation, set the <<Entity>> andromda_persistence_table tag on the entity. The same tag can be modeled on a Many-To-Many association relationship, to name the association table.

images/org/andromda/test/1/c/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

Primary Key - Identifier

To assign an entity's attribute as a primary key, you must assign the <<Identifier>> stereotype to it. If this identifier is not part of a composite primary key, then @javax.persistence.Id annotation is added to the attribute getter method.

images/org/andromda/test/1/d/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

An entity identifier attribute's generator type can be modeled via the <<Identifier>> andromda_persistence_generator_type tag on the identifier attribute ONLY. You do not need to configure the andromda_hibernate_generator_class attribute on the Entity stereotype. This is used to model the primary key generation strategy associated with the @javax.persistence.Id annotation for an entity attribute. Currently, the EJB3 cartridge supports generator types:

  • AUTO which is the default
  • NONE
  • SEQUENCE
  • TABLE

Natural keys must specify a generator type of NONE, in order to override the default type, and also andromda_persistence_assigned_identifier=true. Generally, any non-numeric identifier will be a natural key, typically a 'name' column. Many legacy databases use natural keys for foreign key columns instead of generated identifier values.

andromda_persistence_generator_name specifies the id generator name. The generator name must be a unique name for a persistence unit, which is referenced by one or more classes to be the generator for an entity bean, or else you will get a JPA validation error. By default, if unspecified, the generator name will be 'Entity_generator'. The name is used both in the @javax.persistence.GeneratedValue(strategy=GenerationType.XXX, generator="Entity_generator") and the @javax.persistence.XXXGenerator(name="Entity_generator") where XXX is the type of generator. This specifies either the table name that stores the generated ids or the sequence name which is the name of the database sequence object used to get the ids.

For sequence generator types, you can specify the initial value of the sequence using <<Identifier>> andromda_persistence_generator_initial_value tag and the allocation size by andromda_persistence_generator_allocation_size tag. The allocation size sets the amount to increment by when allocating id numbers from the sequence generator. All of these settings have default values or are allowed to be empty in the annotations.

For a table generator, you must specify the andromda_persistence_generator_pkcolumn_value tag which defines the primary key value in the generator table to identify the specified generated value from other values.

Column Specifics

You can set the column name, size, precision, scale, and DDL definition on entity properties under the <<PersistentProperty>> stereotype. By default the column name is the upperunderscore version of the property name, i.e. firstName is column FIRST_NAME. Associations of multiplicity * are pluralized, so you want to override the default column name. To turn off pluralization, in the andromda.xml default namespace:

<property name="pluralizeAssociationEndNames">false</property>
                    

images/org/andromda/test/1/h/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

To change the default naming schema for the relational table column, model the <<PersistentProperty>> andromda_persistence_schema tag on the attribute.

You can set the column length for the relational database table for string based columns by modeling the andromda_persistence_column_length tag on the attribute. String attributes are by default length 20, if unspecified.

If the column is defined as a decimal column (i.e. float or double), you can model the precision and scale of the column by setting andromda_persistence_column_precision tag to set the precision of the decimal column and/or andromda_persistence_column_scale tag to set the scale for a decimal column, on the attribute. A column defined as NUMBER(35, 2) has a precision of 35 (35 significant digits) and a scale of 2 (number of digits to the right (positive) or left (negative) of the decimal point). For example, Oracle DBMS supports precision 1-38 and scale -84 to 127

In order to change the creation DDL for the column in the relational table, you can model andromda_persistence_column_definition tag on the attribute. This adds the @javax.persistence.Column(columnDefinition="") annotation. This DDL is DBMS specific, may not be portable between local test and dev/prod databases.

Length, precision, scale, and lowerBound (nullable) are automatically validated through the JPA validator annotations, so Entities that fail validation will not be persisted and an error message is returned. For the serial column, the additional validations will be:

@javax.persistence.Size(max=15)

Attribute Multiplicity

It's possible to configure the multiplicity of an entity's property, by setting it to [0..1], meaning the lowerBound is 0 and the property is not required and is allowed to be set to null; setting the multiplicity to a value greater than 0 means the property is required. In the former case the nullable element will be set to true for the @javax.persistence.Column annotation on the property. If not nullable or required, the @javax.persistence.NotNull(message="serial is required") annotation will be added to the property. The following class assigns a multiplicity of [0..1] [lowerBound..upperBound] to the name property which means name can be null.

images/org/andromda/test/1/e/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

Some UML tools have a default multiplicity value for attributes when not specified by the user, these default values may differ from tool to tool.

LowerBound (nullable) property is automatically validated through the Hibernate validator utilities, so Entities that fail validation will not be persisted and an error message is returned. The additional validation will be:

@javax.persistence.NotNull(message="serial is required")

Unique Attributes

If you want an entity's attribute to be unique for all instances of that entity's type, in UML2 mark the attribute as 'Unique'. In UML14, you should assign the <<Unique>> stereotype to it. This will define the corresponding unique element in the @javax.persistence.Column annotation. It will also generate a attribute on the JPA2 @Column(unique=true) annotation, and generate a findByAttribute query, except for identifier properties.

Transient Attribute

To indicate an attribute as transient (not persisted by the persistence container), you model the <<Transient>> stereotype on the attribute. This adds the @javax.persistence.Transient annotation to the attribute.

Insertable Attribute

To include the mapped column in the SQL insert statement, you set the insertable property on the @javax.persistence.Column annotation which is done by modeling the andromda_persistence_column_insert on the attribute. By default, this is set to true, so it only needs to be specified if you want the column to be initialized using the database default value.

Updatable Attribute

To include the mapped column in the SQL update statement, you set the updatable property on the @javax.persistence.Column annotation which is done by modeling the andromda_persistence_column_update on the attribute. By default, this is set to true, so it only needs to be specified if you want the column to be updated using by the database automatically. The attribute will be read-only from the database.

Version Attribute

To specify an attribute as a version attribute, where it becomes the optimistic lock value for an entity, you model the <<Version>> stereotype on this attribute. This can only apply to ONE attribute per class. Attributes with this stereotype will not be updated by the persistent container. The attribute can only of the following types:

  • int
  • short
  • long
  • Integer
  • Short
  • Long
  • Timestamp

Constant Attributes

To define static constants within an entity POJO (constants that are not resource injections), model a classifier scoped attribute (static in Java). These attributes are defined as static with public visibility. Constants must define a default value in the model. The following entity defines 3 constants for type. Static attributes and operations are shown as underlined in the UML model diagram.

images/org/andromda/test/1/f/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

LOB BLOB/CLOB Attributes

An attribute can be specified as either a BLOB or CLOB field. This is modeled by setting the attribute type to datatype::Blob or datatype::Clob. This will add the @javax.persistence.Lob annotation to the entity attribute. The EJB3 cartridge will assign a default Java type based on the Java mappings specified in AndroMDA. For a Blob, the default is byte[]. For a Clob, the default is String. To override the default types, you can model the <<PersistentAttribute>> andromda_persistence_lob_type tagged value to the fully qualified name of the required type.

For BLOB fields, the attribute type must be modeled as one of:

  • Byte[]
  • Serializable type
  • java.sql.Blob

For CLOB fields, the attribute type must be modeled as one of:

  • char[]
  • Character[]
  • String
  • java.sql.Clob

The default fetch type for a LOB typed attribute is lazy. To assign a LOB attribute to be eagerly fetched, model the andromda_persistence_fetch_type tag on the attribute.

images/org/andromda/test/1/g/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

This example models the attribute named type as a CLOB where the corresponding column in the table will be of type String and the cartridge will set the fetch type for the attribute to eagerly fetch. The attribute information is defined as a LOB, but it's of type char[].

Temporal DataTypes

Hibernate supports mapping date, datetime, and time database types to java.util.Data Java type. The type mapping is done through the <<TemporalElement>> andromda_persistence_temporal_type with options of DATE, TIME, TIMESTAMP, and NONE. This results in @javax.persistence.Temporal(TemporalType.XXX) annotation on the attribute.

Custom DataTypes

Custom hibernate type mappings can be used for Enumerations or other types. For example, if a Java boolean type has an underlying column which uses CHAR(1) Y/N values, the PersistentClass stereotype attribute andromda_hibernate_type="yes_no" can be used, resulting in a JPA annotation @org.hibernate.annotations.Type(type="yes_no"). Note that this is a hibernate-specific extension to JPA.

Attribute Fetch Type

By default, the EJB3 cartridge and EJB 3.0 spec defines an attribute fetch type as eagerly fetched. To specify an attribute as lazy fetched, we hint to the persistence container by modeling the <<PersistentAssociationEnd>> andromda_persistence_fetch_type tag on the attribute. Under normal circumstances, you do not need to specify this tag.

Entity Operations

You may also model operations on an entity, this will generate them as methods in the resulting components. Operations can be classifier scoped (static in Java) where they will be underlined in UML diagrams as shown below. You may also define instance scoped operations if you require.

In general, operations will not be defined in the mapped superclass. They will be defined in the inheriting subclass. This has consequences when dealing with a multi-tier inheritance hierarchy. Refer to the inheritance howto for further information. This also implies that operations are only added to the implementation class on the first run of AndroMDA. Operations defined in the UML model must be manually added to the implementation class afterwards. This shouldn't cause any issues, as the developer would have to define the operation implementation anyway to correspond to the abstract definition in the mapped superclass. The primary purpose for this strategy is to avoid having to annotate the entity operation with @javax.persistence.Transient annotation in both the mapped superclass and the inheriting implementation class.

Classifier scoped operations modeled on entity, marked as query operations (finder methods) are not rendered in the entity components, but instead added to the DAO components.

images/org/andromda/test/1/b/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

Entity operations modeled as Query operations are discussed further in the Query Howto. In general entities should NOT contain any business logic. The EJB3 cartridge, like other persistence modeling cartridges, uses the session facade pattern to contain business logic in session bean operations while typical CRUD persistence operations are provided through the DAO layer.

The above example entity models allCarsAreRented() as classifier scoped and isRented() as instance scoped. Both will be added to the entity implementation subclass Car. The bulk of the entity detail, including much of the metadata exists within the CarEmbeddable class. In such cases where non-query operations exists for an entity, the implementation class is generated once only and will not be overridden.

Nullable Parameters

If you want an operation to have a parameter which is allowed to be null then simply set the multiplicity lowerBound to 0 (in UML2). In UML14, assign the <<Nullable>> stereotype to that parameter. By default service operations throw an exception when a null argument has been passed.

It is possible to globally disable checking for null arguments; to do so just specify the

    <property name="parameterRequiredCheck">false</property>

Listener Callback

In some cases, setting up lifecycle event callbacks for the entity beans can be quite useful. The EJB3 cartridge provides the facility to define these callback methods in the listener class. This class is NOT generated by default. To find out more information, click on Listener Callback.

Entity Validations

The following model validations are performed against evey Entity when a model is loaded.

EJB3EntityFacade::entities can only generalize other entities or mapped superclasses

Entity::entities can only specialize other entites

Entity::entity must have at least one primary key

If using a JPA Framework as the ancestor for each entity class, you will want to model the ancestor generalization, include the framework dependency in the core pom.xml, and disable this model validation in andromda.xml through:

<constraints enforceAll="true">
                    <constraint enforce="false">org::andromda::cartridges::ejb3::metafacades::EJB3EntityFacade::entities can only generalize other entities or mapped superclasses</constraint>
                    

Next

Next we will learn about the DAO components generated for the entities, click here to continue.