Project

General

Profile

Actions

CDM Entity Initialization

This page only gives an incomplete view but yet contains some useful documentation on the complex topic of CDM Entity Initialization that is initialization of beans and hibernate proxys in the context of the CDM Library


Bean Initialization

The CDM library is relying on Hibernate as ORM (object relational mapping) framework. Hibernate is responsible for writing CDM entities to the database and for loading them from the persistent store. Let us take the bean class Cdm:agent:Person which inherits several bean properties from Cdm:agent:AgentBase and Cdm:agent:TeamOrPersonBase.

When loading object from the data store Hibernate treats different kinds of bean properties in a different way:

  1. Transient and non-transient bean properties. Hibernate initializes and stores only non-transient bean properties.

  2. Bean properties that return a single non CDM entity. These fields are properties with a primitive return type (e.g. [Cdm:agent:Person:getFirstName()) or with a complex object return type like Cdm:common:TimePeriod which are stored by Hibernate as a string since these fields are Hibernate UserTypes. These properties are always initialized by default.

  3. Bean properties that return a Collection of CDM entities. For example: which returns a Set of [Cdm:agent:Address.

  4. Bean properties that return a single CDM entity. CDM entities are always instances of superclasses of Cdm:common:CdmBase. All properties returning a single or multiple CDM entities will not be initialized after the entity is loaded by Hibernate. For example: When we now try accessing one of these not yet initialized properties Hibernate will transparently initialize the associated CDM entities as long we are in a hibernate session. Outside of a Hibernate session we will experience a LazyLoadingException. In order to make all required Bean properties available we would have to initialize them before the Hibernate session ends. This is where the BeanInitialization mechanisms of the CDM Library come into the game. The cdm:persistance:HibernateBeanInitializer provides methods like [Cdm:persitence:BeanInitializer#initialize(Object bean, List propertyPaths) which take the so called propertyPaths as an argument. The propertyPath defines to which extent CDM entities will be initialized. Each entry in the list of property paths follows a syntax which indicates the properties and transient getters of a specific CDM entity bean which are being initialized by the service.

  • Simple (name) - The specified name identifies an individual property of a particular CDM entity bean. The name of the actual getter method is determined using standard JavaBeans instrospection, so that a property named "xyz" will have a getter method named getXyz() or (for boolean properties only) isXyz(), and a setter method named setXyz().

Nested (name1.name2.name3) The first name element is used to select a property getter, as for simple references above. The object returned for this property is then consulted, using the same approach, for a property getter for a property named name2, and so on. The property value that is ultimately retrieved or modified is the one identified by the last name element.

Indexed (name[index]) - The underlying property value is assumed to be an array, or this JavaBean is assumed to have indexed property getter and setter methods. The appropriate (zero-relative) entry in the array is selected. List objects are now also supported for read/write. You simply need to define a getter that returns the List

*toOne-Wildcard ($) This wildcard is used to select all property getters which reference to one associated bean. A wildcard subsequently terminates a 'property path'.

toAny-Wildcard () This wildcard is used to select all property getters which reference to one associated bean and to to many associated bean. A wildcard subsequently terminates a 'property path'.

Combined (name1.name2[index].$) - Combining mapped, nested, and indexed and wildcard references is also supported.

This syntax description partially is lend from Apache Commons BeanUtils which are being used to inspect the bean properties.

AutoPropertyInitializer

TODO: Description needed

Some examples

In the following we will take a look at different property paths:

  • Initializing a Cdm:agent:person entity with @ {"adresses"} @ will initialize the collection of addresses (@ getAddresses() @)

  • Initializing a Cdm:agent:person entity with @ {"adresses.country"} @ will initialize (@ getAddresses() ) and also getCountry() @ .

  • Initializing a Cdm:agent:person entity with @ {"region"} @ is useless since the return type of getRegion() is a primitive String, so there it is initialized anyway.

  • Initializing a Cdm:agent:Adress entity with @ {"$"} @ will initialize all toOne relations, including @ getCountry() @

  • Initializing a Cdm:agent:person entity with @ {"*"} @ will initialize all relations, including @ getInstitutionalMemberships() @

  • Initializing a Cdm:agent:person entity with @ {"institutionalMemberships.*"} @ will initialize all @ getInstitutionalMemberships() @ and any property of those including @ getInstitute() @ and @ getPerson() @.

cdm remote JSON View

the serialization of cdm entities in the cdmlib-remote package is performed by the net.sf.json library. The serialization in this library can be configured by the JsonConfig class. In this configurator class the property

can be set to ignore bean properties which are annotated with @Transient.

The cdm makes heavy use of this ignorance. Setting this property to false will cause LazyLoadingExceptions and will thus completely break the JSON serialization!!

In the cdm model all getters returning CDM entity or products of CDM entities (algorithms) which are not directly returning a HibernateProxy are annotated as @Transient. In order to serialize these properties you have to do two things:

  1. Explicitly serialize the property by overriding AbstractCdmBeanProcessor.processBeanSecondStep(eu.etaxonomy.cdm.model.common.CdmBase, net.sf.json.JSONObject, JsonConfig) in the according AbstractCdmBeanProcessor@} implementation. If there is no matching @AbstractCdmBeanProcessor implementation you would have to create one. Her an example from @TaxonNameBaseBeanProcessor@:
@Override
public JSONObject processBeanSecondStep(TaxonNameBase bean, JSONObject json, JsonConfig jsonConfig) {
          json.element("taggedName", getTaggedName(bean), jsonConfig);
          return json;
        }
  1. Provide the service method which is used to retrieve the object graph in question with an appropriate initialization strategy.

Updated by Andreas Müller about 1 year ago · 17 revisions