Java Persistence/Mapping

= Mapping = The first thing that you need to do to persist something in Java is define how it is to be persisted. This is called the mapping process (details). There have been many different solutions to the mapping process over the years, including some object databases that didn't require you map anything but let you persist anything directly. Object-relational mapping tools that would generate an object model for a data model that included the mapping and persistence logic in it. ORM products that provided mapping tools to allow the mapping of an existing object model to an existing data model and stored this mapping meta-data in flat files, database tables, XML and finally annotations.

In JPA, mappings can either be stored through Java annotations, or in XML files. One significant aspect of JPA is that only the minimal amount of mapping is required. JPA implementations are required to provide defaults for almost all aspects of mapping an object.

The minimum requirement to mapping an object in JPA is to define which objects can be persisted. This is done through either marking the class with the  annotation, or adding an   tag for the class in the persistence unit's ORM XML file. Also the primary key, or unique identifier attribute(s) must be defined for the class. This is done through marking one of the class' fields or properties (get method) with the  annotation, or adding an   tag for the class' attribute in the ORM XML file.

The JPA implementation will default all other mapping information, including defaulting the table name, column names for all defined fields or properties, cardinality and mapping of relationships, all SQL and persistence logic for accessing the objects. Most JPA implementations also provide the option of generating the database tables at runtime, so very little work is required by the developer to rapidly develop a persistent JPA application.

Access Type
JPA allows annotations to be placed on either the class field, or on the  method for the property. This defines the access type of the class, which is either  or. Either all annotations must be on the fields, or all annotations on the  methods, but not both (unless the   annotation is used). JPA does not define a default access type (oddly enough), so the default may depend on the JPA provider. The default is assumed to occur based on where the  annotation is placed, if placed on a field, then the class is using   access, if placed on a   method, then the class is using   access. The access type can also be defined through XML on the  element. The access type can be configured using the annotation or   XML attribute.

For  access the class field value will be accessed directly to store and load the value from the database. This is normally done either through reflection, or through generated byte code, but depends on the JPA provider and configuration. The field can be  or any other access type. is normally safer, as it avoids any unwanted side-effect code that may occur in the application /  methods.

For  access the class   and   methods will be used to store and load the value from the database. This is normally done either through reflection, or through generated byte code, but depends on the JPA provider and configuration. has the advantage of allowing the application to perform conversion of the database value when storing it in the object. The user should be careful to not put any side-effects in the /  methods that could interfere with persistence.

JPA 2.0 allows the access type to also be set on a specific field or  method. This allows for the class to use one default access mechanism, but for one attribute to use a different access type. This can be used for attributes that need to be converted through a set of database specific,  , or allow a specific attribute to avoid side-affects in its  ,   methods. This is done through specifying the  annotation or XML attribute on the mapped attribute. You may also need to mark the field/property as  if it has a different attribute name than the mapped attribute.

JPA allows for a persistence unit default  element to be set in   or entity default in.


 * TopLink / EclipseLink : Default to using  access.  If weaving is enabled, and field access is used the fields are accessed directly using generated byte-code.  If not using weaving, or using property access, reflection is used.  EclipseLink also supports a third access type , which can be used from the ORM XML to map dynamic properties stored in a properties Map.

My annotations are ignored

 * This typically occurs when you annotate both the fields and methods (properties) of the class. You must choose either field or property access, and be consistent.  Also when annotating properties you must put the annotation on the get method, not the set method.  Also ensure that you have not defined the same mappings in XML, which may be overriding the annotations.  You may also have a classpath issue, such as having an old version of the class on the classpath.

Odd behavior

 * There are many reasons that odd behavior can occur with persistence. One common issue that can cause odd behavior is using property access and putting side effects in your get or set methods.  For this reason it is generally recommended to use field access in mapping, i.e. putting your annotations on your variables not your get methods.


 * For example consider:


 * This may look innocent, but these side effects can have unexpected consequences. For example if the relationship was   this would have the effect of always instantiating the collection when set from the database.  It could also have consequences with certain JPA implementations for persisting, merging and other operations, causing duplicate inserts, missed updates, or a corrupt object model.


 * I have also seen simply incorrect property methods, such as a get method that always returns a new object, or a copy, or set methods that don't actually set the value.


 * In general if you are going to use property access, ensure your property methods are free of side effects. Perhaps even use different property methods than your application uses.

/Mapping