ObjectDB ObjectDB

JPA Persistable Types

The term persistable types refers to data types that can be used for storing data in the database. ObjectDB supports all the JPA persistable types, which are:

  • User defined classes - Entity classes, Mapped superclasses, Embeddable classes.
  • Simple Java data types: Primitive types, Wrappers, String, Date and Math types.
  • Multi value types - Collections, Maps and Arrays.
  • Miscellaneous types: Enum types and Serializable types (user or system defined).

Note: Only instances of entity classes can be stored in the database directly. Other persistable types can be embedded in entity classes as fields. In addition, only instances of entity classes preserve identity and are stored only once even if they are referenced multiple times. Referencing instances of other persistable types from multiple persistent fields would cause data duplication in the database.

Entity Classes

An entity class is an ordinary user defined Java class whose instances can be stored in the database. The easy way to declare a class as an entity is to mark it with the Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page... annotation:

import javax.persistence.Entity;

@javax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class MyEntity {
  
}

Entity Class Requirements

A portable JPA entity class:

  • should be a top-level class (i.e. not a nested / inner class).
  • should have a public or protected no-arg constructor.
  • cannot be final and cannot have final methods or final instance variables.

ObjectDB is slightly less restrictive:

  • Static nested entity classes are allowed (non static inner classes are forbidden).
  • Instance (non static) variables cannot be final, but classes and methods can be final.
  • In most cases ObjectDB can overcome a missing no-arg constructor.

Aside from these constraints, an entity class is like any other Java class. It can extend either another entity class or a non-entity user defined class (but not system classes, such as ArrayList) and implement any interface. It can contain constructors, methods, fields and nested types with any access modifiers (public, protected, package or private) and it can be either concrete or abstract.

Entity Class Names

Entity classes are represented in queries by entity names. By default, the entity name is the unqualified name of the entity class (i.e. the short class name excluding the package name). A different entity name can be set explicitly by using the nameEntity.nameannotation element(Optional) The entity name.See JavaDoc Reference Page... attribute of the Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page... annotation:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...(nameEntity.nameannotation element(Optional) The entity name.See JavaDoc Reference Page...="MyName")
public class MyEntity {

}

Entity names must be unique. When two entity classes in different packages share the same class name, explicit entity name setting is required to avoid clashes.

Mapped Superclasses

In JPA, classes that are declared as mapped superclasses have some of the features of entity classes, but also some restrictions. ObjectDB, however, does not enforce these restrictions so mapped superclasses are treated by ObjectDB as ordinary entity classes.

Mapped superclasses are really only useful in applications that use an ORM-based JPA provider (such as Hibernate, TopLink, EclipseLink, OpenJPA, JPOX, DataNucleus, etc.).

Embeddable Classes

Embeddable classes are user defined persistable classes that function as value types. As with other non entity types, instances of an embeddable class can only be stored in the database as embedded objects, i.e. as part of a containing entity object.

A class is declared as embeddable by marking it with the Embeddablejavax.persistence.EmbeddableJPA annotationDefines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity.See JavaDoc Reference Page... annotation:

@Embeddablejavax.persistence.EmbeddableJPA annotationDefines a class whose instances are stored as an intrinsic 
 part of an owning entity and share the identity of the entity.See JavaDoc Reference Page...
public class Address {
    String street;
    String city;
    String state;
    String country;
    String zip;
}

Instances of embeddable classes are always embedded in other entity objects and do not require separate space allocation and separate store and retrieval operations. Therefore, using embeddable classes can save space in the database and improve efficiency.

Embeddable classes, however, do not have an identity (primary key) of their own which leads to some limitations (e.g. their instances cannot be shared by different entity objects and they cannot be queried directly), so a decision whether to declare a class as an entity or embeddable requires case by case consideration.

Simple Java Data Types

All the following simple Java data types are persistable:

  • Primitive types: boolean, byte, short, char, int, long, float and double.
  • Equivalent wrapper classes from package java.lang:
    Boolean, Byte, Short, Character, Integer, Long, Float and Double.
  • java.math.BigInteger, java.math.BigDecimal.
  • java.lang.String.
  • java.util.Date, java.util.Calendar,
    java.sql.Date, java.sql.Time, java.sql.Timestamp.

Date and time types are discussed in more detail in the next paragraph.

Date and Time (Temporal) Types

The java.sql date and time classes represent different parts of dates and times:

  • java.sql.Date - represents date only (e.g. 2019-12-31).
  • java.sql.Time - represents time only (e.g. 23:59:59).
  • java.sql.Timestamp - represents date and time (e.g. 2019-12-31 23:59:59).

The java.util.Date and java.util.Calendar types, on the other hand, are generic and can represent any of the above, using the @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar.See JavaDoc Reference Page... JPA annotation:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class DatesAndTimes {
    // Date Only:
    java.sql.Date date1;
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....DATETemporalType.DATEenum constantMap as java.sql.DateSee JavaDoc Reference Page...) java.util.Date date2
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....DATETemporalType.DATEenum constantMap as java.sql.DateSee JavaDoc Reference Page...) java.util.Calendar date3;

    // Time Only:
    java.sql.Time time1;
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....TIMETemporalType.TIMEenum constantMap as java.sql.TimeSee JavaDoc Reference Page...) java.util.Date time2;
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....TIMETemporalType.TIMEenum constantMap as java.sql.TimeSee JavaDoc Reference Page...) java.util.Calendar time3;

    // Date and Time:
    java.sql.Timestamp dateAndTime1;
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....TIMESTAMPTemporalType.TIMESTAMPenum constantMap as java.sql.TimestampSee JavaDoc Reference Page...) java.util.Date dateAndTime2;
    @Temporaljavax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields 
 or properties of type java.util.Date and 
 java.util.Calendar.See JavaDoc Reference Page...(TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date 
 or java.util.Calendar.See JavaDoc Reference Page....TIMESTAMPTemporalType.TIMESTAMPenum constantMap as java.sql.TimestampSee JavaDoc Reference Page...) java.util.Calendar dateAndTime3;
    java.util.Date dateAndTime4; // date and time, not JPA portable
    java.util.Calendar dateAndTime5; // date and time, not JPA portable  
}

Persisting pure dates (without the time part), either by using the java.sql.Date type or by specifying the @Temporal(javax.persistence.TemporalJPA annotationThis annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar.See JavaDoc Reference Page...TemporalTypejavax.persistence.TemporalTypeJPA enumType used to indicate a specific mapping of java.util.Date or java.util.Calendar.See JavaDoc Reference Page....DATETemporalType.DATEenum constantMap as java.sql.DateSee JavaDoc Reference Page...) annotation has several benefits:

  • It saves space in the database.
  • It is more efficient (storage and retrieval are faster).
  • It simplifies queries on dates and ranges of dates.

When an entity is stored, its date and time fields are automatically adjusted to the requested mode. For example, fields date1, date2 and date3 above may be initialized as new Date(), i.e. with both date and time. Their time part is discarded when they are stored in the database.

Multi Value Types

The following multi value types are persistable:

  • Collection types from package java.util: ArrayList, Vector, Stack, LinkedList, ArrayDeque, PriorityQueue, HashSet, LinkedHashSet, TreeSet.
  • Map types from package java.util: HashMap, Hashtable, WeakHashMap, IdentityHashMap, LinkedHashMap, TreeMap and Properties.
  • Arrays (including multi dimensional arrays).

Both generic (e.g. ArrayList<String>) and non generic (e.g. ArrayList) collection and map types are supported, as long as their values (i.e. elements in collections and arrays and keys and values in maps) are either null values or instances of persistable types.

In addition to the collection and map classes that are fully supported by ObjectDB, any other class that implements java.util.Collection or java.util.Map can be used when storing entities. If an unsupported collection or map type is used, ObjectDB will switch to a similar supported type when the data is retrieved from the database.

For example, the Arrays.asList method returns an instance of an internal Java collection type that is not supported by ObjectDB. Nevertheless, the following entity can be stored:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class EntityWithList {
    private List<String> words = Arrays.asList("not", "ArrayList");
}

When the entity is retrieved from the database, the list will be instantiated as an ArrayList. Using an interface (List<String>) for the field type is essential in this case to enable switching to the supported collection type when the entity is retrieved. Actually, JPA requires declaring persistent collection and map fields only as interface types (i.e. java.util.Collection, java.util.List, java.util.Set, java.util.Map), and that is also a good practice when working with ObjectDB.

Proxy Classes

When entities are retrieved from the database, instances of mutable persistable system types (i.e. collections, maps and dates) are instantiated using proxy classes that extend the original classes and enable transparent activation and transparent persistence.

For example, a collection that is stored as an instance of java.util.ArrayList is retrieved from the database as an instance of objectdb.java.util.ArrayList, which is a subclass of the original java.util.ArrayList.

Most applications are not affected by this, because proxy classes extend the original Java classes and inherit their behavior. The difference can be noticed in the debugger view and when invoking the getClass method on an object of such proxy classes.

Enum Types

Every enum type (user defined or system defined) is persistable. But, if future portability to other platforms is important, only values of user defined enum types should be persisted.

By default, enum values are represented internally by their ordinal numbers. Caution is required when modifying an enum type that is already in use in an existing database. New enum fields can be added safely only at the end (with new higher ordinal numbers).

Alternatively, enum values can be represented internally by their names. In that case, the names must be fixed, since changing a name can cause data loss in existing databases.

The @Enumeratedjavax.persistence.EnumeratedJPA annotationSpecifies that a persistent property or field should be persisted as a enumerated type.See JavaDoc Reference Page... annotation enables choosing the internal representation:

@Entityjavax.persistence.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
public class Style {
    Color color1; // default is EnumType.ORDINAL
    @Enumeratedjavax.persistence.EnumeratedJPA annotationSpecifies that a persistent property or field should be persisted
 as a enumerated type.See JavaDoc Reference Page...(EnumTypejavax.persistence.EnumTypeJPA enumDefines mapping for enumerated types.See JavaDoc Reference Page....ORDINALEnumType.ORDINALenum constantPersist enumerated type property or field as an integer.See JavaDoc Reference Page...) Color color2;
    @Enumeratedjavax.persistence.EnumeratedJPA annotationSpecifies that a persistent property or field should be persisted
 as a enumerated type.See JavaDoc Reference Page...(EnumTypejavax.persistence.EnumTypeJPA enumDefines mapping for enumerated types.See JavaDoc Reference Page....STRINGEnumType.STRINGenum constantPersist enumerated type property or field as a string.See JavaDoc Reference Page...) Color color3;
}

enum Color { RED, GREEN, BLUE }; 

In the above example, values of the color1 and color2 fields are stored as ordinal numbers (i.e. 0, 1, 2) while values of the color3 field are stored internally as strings (i.e. “RED”, “GREEN”, “BLUE”).

Serializable Types

Every serializable class (user defined or system defined) is also persistable, but relying on serialization in persisting data has a severe drawback in terms of lack of portability. The internal Java serialization format will be inaccessible to future versions of ObjectDB on other platforms (e.g. .NET). Therefore, it is recommended to only use explicitly specified persistable types.

Serialization is disabled by default.