Jump to: navigation, search

Difference between revisions of "EclipseLink/FAQ/JPA"

(How to access what changed in an object or transaction?)
m (Starting with release 2.5.0, EclipseLink supports SAP HANA database: http://wiki.eclipse.org/EclipseLink/Development/DatabasePlatform/HANAPlatform)
(13 intermediate revisions by 2 users not shown)
Line 65: Line 65:
 
* SQL Anywhere
 
* SQL Anywhere
 
* HSQL
 
* HSQL
 +
* SAP HANA
 
* H2
 
* H2
 
* Firebird
 
* Firebird
Line 97: Line 98:
 
EclipseLink supports NoSQL databases and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).
 
EclipseLink supports NoSQL databases and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).
  
See [[EclipseLink/FAQ/NoSQL|NoSQL]].
+
See [[EclipseLink/FAQ/NoSQL|NoSQL]] and the [http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_nosql.htm JPA Extensions Guide] for details.
  
 
==How is EclipseLink integrated with the Oracle database?==
 
==How is EclipseLink integrated with the Oracle database?==
Line 224: Line 225:
 
* Database - the database is deadlocked on a set of transactions.
 
* Database - the database is deadlocked on a set of transactions.
 
** You will see JDBC access as the last call on the stack.
 
** You will see JDBC access as the last call on the stack.
** This is normally causes by database table, row and page locks.
+
** This is normally caused by database table, row and page locks.
 
** Check for usages of pessimistic locking, or concurrent updates to the same set of rows.
 
** Check for usages of pessimistic locking, or concurrent updates to the same set of rows.
 +
** If a set of updates is deadlocking, trying setting the persistence unit property "eclipselink.order-updates"="true".
 
** EclipseLink avoids database deadlocks through several mechanisms, including providing optimistic locking, a read and sequence connection pool, and ordering writes by table, and ordering updates and deletes by id.
 
** EclipseLink avoids database deadlocks through several mechanisms, including providing optimistic locking, a read and sequence connection pool, and ordering writes by table, and ordering updates and deletes by id.
 
** Ensure a sequence connection pool is being used if using TABLE sequencing.  See [http://www.eclipse.org/eclipselink/api/2.3/org/eclipse/persistence/config/PersistenceUnitProperties.html#CONNECTION_POOL_SEQUENCE PersistenceUnitProperties.CONNECTION_POOL_SEQUENCE];
 
** Ensure a sequence connection pool is being used if using TABLE sequencing.  See [http://www.eclipse.org/eclipselink/api/2.3/org/eclipse/persistence/config/PersistenceUnitProperties.html#CONNECTION_POOL_SEQUENCE PersistenceUnitProperties.CONNECTION_POOL_SEQUENCE];
Line 263: Line 265:
  
 
==How to access what changed in an object or transaction?==
 
==How to access what changed in an object or transaction?==
EclipseLink tracks changes made to managed objects within a persistence context or transaction.  Changes are tracked in two main different ways, depending on your objects and configuration.  These are defined in the ChangeTrackingType enum, and are either ATTRIBUTE, OBJECT or DEFERRED.
+
EclipseLink tracks changes made to managed objects within a persistence context or transaction.  This allows EclipseLink to update only exactly what changed.  Changes are tracked in two main different ways, depending on your objects and configuration.  These are defined in the ChangeTrackingType enum, and are either ATTRIBUTE, OBJECT or DEFERRED.
  
 
ATTRIBUTE weaves a PropertyChangeListener into your class.  Whenever any field in your class changes, this listener is notified of the change.  ATTRIBUTE is used when weaving is enabled through dynamic or static weaving.
 
ATTRIBUTE weaves a PropertyChangeListener into your class.  Whenever any field in your class changes, this listener is notified of the change.  ATTRIBUTE is used when weaving is enabled through dynamic or static weaving.
  
 
DEFERRED does not require any class changes, so is used when weaving is not enabled.  A backup copy of the object is made when it is first registered in the persistence context.  On commit or flush, the current managed state of the object is compared to the backup to determine the changes.
 
DEFERRED does not require any class changes, so is used when weaving is not enabled.  A backup copy of the object is made when it is first registered in the persistence context.  On commit or flush, the current managed state of the object is compared to the backup to determine the changes.
 +
 +
OBJECT uses a combination of the two.
  
 
EclipseLink creates instances of ObjectChangeSet that capture the changes made to an object.  EclipseLink uses these change sets internally, but they are also available to the application if it also requires to know what has changed.  There are two ways to access the change sets, directly from the UnitOfWork, and through events.
 
EclipseLink creates instances of ObjectChangeSet that capture the changes made to an object.  EclipseLink uses these change sets internally, but they are also available to the application if it also requires to know what has changed.  There are two ways to access the change sets, directly from the UnitOfWork, and through events.
Line 280: Line 284:
 
</source>
 
</source>
  
To access changes from events, EclipseLink's DescriptorEvents must be used.  Descriptor events can be registered for using a DescriptorEventListener similar to using an EntityListener.  DescriptorEventListener has events for pre/post/aboutTo Update/Insert/Delete.  You can access the object from the event using <code>getObject</code> and you can access the change set using <code>getChangeSet</code>
+
To access changes from events, EclipseLink's DescriptorEvents must be used.  Descriptor events can be registered for using a DescriptorEventListener similar to using an EntityListener.  DescriptorEventListener has events for pre/post/aboutTo Update/Insert/Delete.  You can access the object from the event using <code>getObject</code> and you can access the change set using <code>getChangeSet</code>, or <code>getQuery().getObjectChangeSet()</code>.
  
 
<source lang="java">
 
<source lang="java">
 
public void MyEventListener extends DescriptorEventAdapter {
 
public void MyEventListener extends DescriptorEventAdapter {
 
   public void postUpdate(DescriptorEvent event) {
 
   public void postUpdate(DescriptorEvent event) {
     ObjectChangeSet objectChanges = event.getChangeSet();
+
     ObjectChangeSet objectChanges = ((UpdateObjectQuery)event.getQuery()).getObjectChangeSet();
 
     DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
 
     DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
 
     Object newValue = change.getNewValue();
 
     Object newValue = change.getNewValue();
Line 291: Line 295:
 
     ...
 
     ...
 
   }
 
   }
 +
}
 +
</source>
 +
 +
If you object is weaved for attribute change tracking, you can access the change set directly from the object.
 +
 +
<source lang="java">
 +
ObjectChangeSet objectChanges = ((AttributeChangeListener)((ChangeTracker)object)._persistence_getPropertyChangeListener()).getObjectChangeSet();
 +
DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
 +
Object newValue = change.getNewValue();
 +
Object oldValue = change.getOldValue();
 +
</source>
 +
 +
* JavaDoc for [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/sessions/changesets/package-frame.html changesets] package.
 +
 +
==How to avoid trimming the trailing spaces on a CHAR field?==
 +
Most databases support both CHAR and VARCHAR column types.  VARCHAR is by far the more commonly used type as it supports variable length strings.  Historically legacy databases only had CHAR types, so they can be more common in legacy database integration.  Most modern schemas use VARCHAR types, and this is by far the recommended option.
 +
 +
A CHAR type is always fixed sized, so if you insert "ABA" into a CHAR column of size 5, it will be stored in the database with trailing spaces as <code>"ABA&nbsp;&nbsp;"</code>.  Normally when you select it back you will get <code>"ABA&nbsp;&nbsp;"</code>, which is normally not desirable.  This is why EclipseLink by default trims the trailing spaces from CHAR field values.  Sometimes the application desires the space padding, so CHAR trimming can be disabled in EclipseLink.
 +
 +
To disable the trimming of CHAR fields a <code>SessionCustomizer</code> can be used.
 +
 +
<source lang="java">
 +
public MyCustomizer implements SessionCustomizer {
 +
  public customize(Session session) {
 +
    session.getLogin().setShouldTrimStrings(false);
 +
  }
 +
}
 
</source>
 
</source>
  
* JavaDoc for [http://www.eclipse.org/eclipselink/api/2.3/org/eclipse/persistence/sessions/changesets/package-frame.html changesets] package.
 
  
 
[[Category:EclipseLink FAQ|JPA]]
 
[[Category:EclipseLink FAQ|JPA]]

Revision as of 03:31, 11 September 2013

What is Object-Relational Mapping

Object-relational mapping or ORM is the category of products that provide services to map objects to relational databases. The Java Persistence API (JPA) is the Java specification that provides a standard to ORM in Java. JPA provides both a standard mapping definition (through annotations or XML) and a standard runtime API and object-level query language (JPQL). JPA is part of the EJB specification and JEE platform, but can also be used in JSE.

EclipseLink provides sophisticated and high performance object-relational mapping services and complete support for the JPA specification. JPA objects are mapped through the package javax.persistence annotations and JPA persistence.xml and orm.xml. EclipseLink also provides extended annotations through the package org.eclipse.persistence.annotations. JPA provides a runtime API through the EntityManager class in the javax.persistence package. EclipseLink also provides extended runtime API through the package org.eclipse.persistence.jpa.

EclipseLink also provides a POJO ORM API and mapping model which its JPA support is based on. The mapping model classes are in the org.eclipse.persistence.descriptors and org.eclipse.persistence.mappings packages, and sessions.xml and project.xml files. The runtime API is provided through the Session and UnitOfWork classes in the org.eclipse.persistence.sessions package.

What are the Best Practices for using EclipseLink JPA?

See EclipseLink JPA Best Practices.

What version of JPA does EclipseLink support?

EclipseLink fully supports JPA 2.0, in fact, EclipseLink is the JPA 2.0 reference implementation.

EclipseLink can also be used the Java EE servers that only support JPA 1.0.

EclipeLink 2.4 also supports some aspects of the JPA 2.1 draft.

What features beyond JPA does EclipseLink support?

EclipseLink provides additional features beyond the JPA specification.

These include:

  • Caching: shared/isolated/protected/read-only, clustered cache coordination, invalidation, indexes, in-memory querying, database events driven invalidation
  • Mapping: converters, history, additional criteria, interfaces, variable relationships, field locking, query keys, UUID
  • JPQL: FUNC, TREAT, ON, FUNCTION, OPERATOR, SQL, TABLE, COLUMN, CAST, EXTRACT, REGEXP, FROM sub-select, SELECT sub-select, NULLS FIRST/LAST, UNION, INTERSECT, EXCEPT
  • Querying: join fetch, batch fetch, fetch groups, connect by, SQL hints, cursors, map results, fetch-size, timeouts, expressions, stored procedures
  • Performance: data partitioning/sharding, batch writing, weaving
  • Connection pooling: min/max/initial, read pool, query retry, DataSource, JTA, UCP
  • Composite persistence units: multi-database integration
  • Dynamic: dynamic entities, extensions, external meta-data
  • Object-relational: Struct and Array data-types
  • Extendable: descriptor/session customizers, custom converters, custom inheritance, custom joins, custom partitioning, descriptor/session events
  • DDL: schema create/replace/extend, indexes, cascade delete
  • Database: Oracle, MySQL, PostgreSQL, DB2, SQL Server, Sybase, SQL Anywhere, Informix, Derby, Firebird, H2, HSQL, MaxDB, Symfoware, Access, Attunity, Cloudscape, DBase, PointBase, TimesTen
  • Oracle: RAC, UCP, XDB, spatial, lobs, NChar, timestamptz, QCN/DCN, VPD, flashback, returning, PLSQL
  • NoSQL: MongoDB, Oracle NoSQL, XML files, JMS, Oracle AQ, JCA
  • Java EE: WebLogic, Glassfish, WebSphere, JBoss
  • OSGi, Spring

Migrating to EclipseLink JPA

How do I migrate from using Oracle TopLink to EclipseLink?

See Oracle TopLink

How do I migrate from using TopLink Essentials to EclipseLink?

See TopLink Essentials

How do I migrate from another JPA provider to EclipseLink?

See JPA Migration

What databases are supported?

EclipseLink supports any relational database that is compliant with SQL and has a compliant JDBC driver. EclipseLink has extended support for several database platforms. The extended support mainly consists of providing native sequencing support, schema creation, and certain database functions. These platform classes can be found in the org.eclipse.persistence.platform.database and org.eclipse.persistence.platform.database.oracle packages.

These include:

  • Oracle
  • Oracle JDBC (8, 9, 10, 11)
  • MySQL
  • PostgreSQL
  • Derby
  • DB2
  • DB2 (mainframe)
  • Microsoft SQL Server
  • Sybase
  • Informix
  • SQL Anywhere
  • HSQL
  • SAP HANA
  • H2
  • Firebird
  • Microsoft Access
  • Attunity
  • Cloudscape
  • DBase
  • PointBase
  • TimesTen
  • Symfoware
  • MaxDB

It also possible to extend EclipseLink to add extended support for additional platforms. There are also several user contributed platforms in the EclipseLink incubator project, see Platform Incubator.

EclipseLink has extended support for Oracle JDBC drivers. Including:

  • LOB's
  • NChar's
  • XMLType's
  • TIMESTAMP (TZ, LTZ)'s
  • Native batch writing
  • Structured object-relational data-types
  • PLSQL data-types and stored procedures
  • VPD, RAC, proxy authentication
  • XDK XML parser

EclipseLink also has support for structure object-relational data-types and databases, and NoSQL and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).

See NoSQL.

Does EclipseLink support NoSQL databases?

EclipseLink supports NoSQL databases and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).

See NoSQL and the JPA Extensions Guide for details.

How is EclipseLink integrated with the Oracle database?

EclipseLink is completely independent from, but also tightly integrated with the Oracle database. EclipseLink has extended support for most Oracle SQL, JDBC and database extensions.

EclipseLink's extended support for the Oracle database includes:

  • LOB's
  • NChar's
  • XMLType's
  • TIMESTAMP (TZ, LTZ)'s
  • Native batch writing
  • Structured object-relational data-types
  • PLSQL data-types and stored procedures
  • VPD, RAC, proxy authentication
  • XDK XML parser
  • Hierarchical selects (connect by prior)
  • Returning clause
  • Flashback history and queries
  • Stored procedures, output parameters and output cursors
  • Stored functions
  • Oracle AQ

How to access table, column and schema information at runtime?

EclipseLink stores the mapping metadata from the JPA annotations and orm.xml in its ClassDescriptor and DatabaseMapping objects. These objects can be accessed at runtime from the EntityManager or EntityManagerFactory by casting or unwrapping to the EclipseLink JPA interface.

EntityManager em = getEntityManager();
String table = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getTables().get(0).getName();
String schema = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getTables().get(0).getTableQualifier();
String column = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getMappingForAttributeName("myAttribute").getField().getName();

If you use JPA annotations, you may also be able to access specified schema information using Java reflection to access your annotation objects.

The JPA 2.0 metamodel can also be used to provide information on how the attributes are mapped (but not their database schema information).

You can also use native SQL queries to query your database catalogs for schema information, or use the JDBC connection metadata APIs. EclipseLink also exposes the JDBC catalog APIs through its SchemaManager class.

How to access the JDBC connection?

Sometimes when using JPA it may be required to have lower level access to your database through JDBC. If you are using a JEE DataSource, you can just access the same DataSource that JPA uses, if it is a JTA DataSource it will be in the same transaction context as JPA.

If you are not using a DataSource, or want the same connection in the same transaction as JPA, you can obtain the JDBC Connection from the EntityManager.

See, Getting a JDBC Connection from an EntityManager

How to disable or enable weaving?

In a Java SE environment weaving is not enabled by default. This can affect LAZY OneToOne, ManyToOne and Basic relationships. It also has a major effect on performance and disable attribute change tracking.

To enable weaving in Java SE, the EclipseLink agent must be used when starting the Java VM.

 java -javaagent:eclipselink.jar

Spring could also be used to allow JPA weaving in Java SE.

Static weaving can also be used to weave your jar.

See, How to Configure Static Weaving

In a Java EE environment weaving is enabled by default (on any JEE EJB 3.0 fully compliant app server, Weblogic, Webspehere, Glassfish. JBoss does not allow weaving so you must use static weaving or Spring).

To disable weaving the weaving persistence unit property can be used,

 <property name="eclipselink.weaving" value="false">

For more information on weaving see the EclipseLink UserGuide, Using EclipseLink JPA Weaving

Are stored procedures and triggers supported?

EclipseLink has extended support for stored procedures and triggers.

Stored procedures are support through the @NamedStoredProcedureQuery, @NamedStoredFunctionQuery, @NamedPLSQLStoredFunctionQuery, @NamedPLSQLStoredProcedureQuery, StoredProcedureCall, StoredFunctionCall, PLSQLStoredProcedureCall, and PLSQLStoredFunctionCall classes.

The following stored procedures features are supported:

  • IN parameters
  • OUT parameter
  • INOUT parameters
  • result sets
  • CURSOR OUT parameters
  • Object-relational datatypes (Struct, Array)
  • Oracle PLSQL types such as TABLE, RECORD, BOOLEAN
  • Using a stored procedure in a named query
  • Using a stored procedure in a dynamic query
  • Using a stored procedure to override an Entity's persist, update, remove or find query.
  • Using a stored procedure to override a mapping's select, insert or delete query.
  • Stored functions
  • Oracle, SQL Server, MySQL, Sybase, DB2, other stored procedure capable platforms


Triggers can be used in the tables being processed by EclipseLink.

If a trigger is updating data required back in the application, or the id, the @ReturnInsert, @ReturnUpdate or ReturningPolicy can be used the return the values updated by the trigger.

How to get the SQL for a Query?

To see the SQL for a JPA Query you can enable logging on FINE or lower.

To get the SQL for a specific Query at runtime you can use the DatabaseQuery API.

Session session = em.unwrap(JpaEntityManager).getActiveSession();
DatabaseQuery databaseQuery = ((EJBQueryImpl)query).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
String sqlString = databaseQuery.getSQLString();

This SQL will contain ? for parameters. To get the SQL translated with the arguments you need a DatabaseRecord with the parameter values.

Session session = em.unwrap(JpaEntityManager).getActiveSession();
DatabaseQuery databaseQuery = ((EJBQueryImpl)query).getDatabaseQuery();
String sqlString = databaseQuery.getTranslatedSQLString(session, recordWithValues);

How to diagnose and resolve hangs and deadlocks?

A system hang, or deadlock is one of the most difficult problems to diagnose and resolve.

The first task is to determine where the application is hanging.

Use ctrl<break> on Windows or kill on Unix, or a debugger to log the stack trace to identify what the hung threads are blocked on.

Possible sources include:

  • Application - the application uses locks or synchronized methods causing the hang.
    • This should be the easiest to diagnose, as it is within your own code.
  • Database - the database is deadlocked on a set of transactions.
    • You will see JDBC access as the last call on the stack.
    • This is normally caused by database table, row and page locks.
    • Check for usages of pessimistic locking, or concurrent updates to the same set of rows.
    • If a set of updates is deadlocking, trying setting the persistence unit property "eclipselink.order-updates"="true".
    • EclipseLink avoids database deadlocks through several mechanisms, including providing optimistic locking, a read and sequence connection pool, and ordering writes by table, and ordering updates and deletes by id.
    • Ensure a sequence connection pool is being used if using TABLE sequencing. See PersistenceUnitProperties.CONNECTION_POOL_SEQUENCE;
    • Avoid using a SERIALIZABLE or strict database transaction isolation level.
  • Connection pool - the application has exceed the size of the connection pool and a thread with a connection requires an additional connection.
    • You will see a connection request as the last method on the stack.
    • Ensure an adequate number of connections in your connection pool.
  • Cache - If using a shared cache, EclipseLink requires locking the cache on reads and writes to ensure consistency.
    • You will see cache access, such as IdentityMapManager acquireLock or acquireDeferredLock, or WriteLockManager as the last call on the stack.
    • Ensure you are using the latest EclipseLink release, the issue may have been fixed. Otherwise log a bug including the relevant stack dump.
    • This is normally related to having relationships that do not use LAZY, ensure all relationship use LAZY.
      • An alternative to using LAZY is to set the persistence unit property, "eclipselink.weaving.eager"="true".
    • It can also be caused by join fetching, so remove any join fetches to diagnose the problem.
    • A workaround is to disable the shared cache. See How to disable the shared cache?.
    • The cache isolation in EclipseLink can be configured. Try using a SessionCustomizer to call session.getLogin().setCacheTransactionIsolation(CONCURRENT_READ_WRITE).
    • A possible workaround is to configure DeferredLockManager.SHOULD_USE_DEFERRED_LOCKS = false.

Do I have to maintain both sides of a bi-directional relationship?

Yes, you need to maintain both sides of the relationship in JPA. It is a common problem that an application does not do this, and then sees inconsistent objects afterwords. This is normally not done by mistake, but is also done on purpose, normally with a ManyToOne/OneToMany relationship, where the application programmer wants to avoid the cost of reading in the OneToMany collection, especially if it is large.

If you are updating a child in a OneToMany, then you just need to find() it, and update it, or use merge(). You do not need to merge() or modify the parent or its children relationship.

If you are adding a new child, then you need to persist() or merge() it, set its parent to the one from the current persistence context using find() (merge can do this, but if your parent is transient, or nulled out, then you need to do this yourself, and if the parent's children are transient or nulled out, then you need to be careful it is not merged or cascaded). You also need to add the child to the parent's children (otherwise it will not be there in the current persistence context, or possibly future ones if you are using a shared cache).

If you are deleting a child, then you need to call remove() on it, unless you have set the relationship to deleteOrphans. You also need to remove it from the parent's children, (otherwise it will still be there in the current persistence context, or possibly future ones if you are using a shared cache).

There are alternatives to adding and removing the child though, if you want to avoid the cost of reading the children:

  • If you are using LAZY relationship, a List (it is also possible with Set, but there can be issues), and weaving (static or dynamic), then add() and remove() will not instantiate the children.
  • If the children is not something you want to ever read, then consider not mapping it, just query it if needed.
  • If the parent's children is not instantiated, you could avoid adding the child. (see PersistenceUnitUtil.isLoaded()).
  • You can call refresh() on the parent after the commit to reset its children.
  • You can avoid adding the child if you clear or throw away your persistence unit, and are not using a shared cache.

How to access what changed in an object or transaction?

EclipseLink tracks changes made to managed objects within a persistence context or transaction. This allows EclipseLink to update only exactly what changed. Changes are tracked in two main different ways, depending on your objects and configuration. These are defined in the ChangeTrackingType enum, and are either ATTRIBUTE, OBJECT or DEFERRED.

ATTRIBUTE weaves a PropertyChangeListener into your class. Whenever any field in your class changes, this listener is notified of the change. ATTRIBUTE is used when weaving is enabled through dynamic or static weaving.

DEFERRED does not require any class changes, so is used when weaving is not enabled. A backup copy of the object is made when it is first registered in the persistence context. On commit or flush, the current managed state of the object is compared to the backup to determine the changes.

OBJECT uses a combination of the two.

EclipseLink creates instances of ObjectChangeSet that capture the changes made to an object. EclipseLink uses these change sets internally, but they are also available to the application if it also requires to know what has changed. There are two ways to access the change sets, directly from the UnitOfWork, and through events.

To access the current changes from an EntityManager:

UnitOfWorkChangeSet changes = em.unwrap(UnitOfWork.class).getCurrentChanges();
ObjectChangeSet objectChanges = changes.getObjectChangeSetForClone(object);
DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
Object newValue = change.getNewValue();
Object oldValue = change.getOldValue();

To access changes from events, EclipseLink's DescriptorEvents must be used. Descriptor events can be registered for using a DescriptorEventListener similar to using an EntityListener. DescriptorEventListener has events for pre/post/aboutTo Update/Insert/Delete. You can access the object from the event using getObject and you can access the change set using getChangeSet, or getQuery().getObjectChangeSet().

public void MyEventListener extends DescriptorEventAdapter {
  public void postUpdate(DescriptorEvent event) {
    ObjectChangeSet objectChanges = ((UpdateObjectQuery)event.getQuery()).getObjectChangeSet();
    DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
    Object newValue = change.getNewValue();
    Object oldValue = change.getOldValue();
    ...
  }
}

If you object is weaved for attribute change tracking, you can access the change set directly from the object.

ObjectChangeSet objectChanges = ((AttributeChangeListener)((ChangeTracker)object)._persistence_getPropertyChangeListener()).getObjectChangeSet();
DirectToFieldChangeRecord change = (DirectToFieldChangeRecord)objectChanges.getChangesForAttributeNamed("firstName");
Object newValue = change.getNewValue();
Object oldValue = change.getOldValue();

How to avoid trimming the trailing spaces on a CHAR field?

Most databases support both CHAR and VARCHAR column types. VARCHAR is by far the more commonly used type as it supports variable length strings. Historically legacy databases only had CHAR types, so they can be more common in legacy database integration. Most modern schemas use VARCHAR types, and this is by far the recommended option.

A CHAR type is always fixed sized, so if you insert "ABA" into a CHAR column of size 5, it will be stored in the database with trailing spaces as "ABA  ". Normally when you select it back you will get "ABA  ", which is normally not desirable. This is why EclipseLink by default trims the trailing spaces from CHAR field values. Sometimes the application desires the space padding, so CHAR trimming can be disabled in EclipseLink.

To disable the trimming of CHAR fields a SessionCustomizer can be used.

public MyCustomizer implements SessionCustomizer {
  public customize(Session session) {
    session.getLogin().setShouldTrimStrings(false);
  }
}