JPA Persistable Types
Persistable types are data types that can be used for storing data in the database. ObjectDB supports all JPA persistable types, which include:
- User-defined classes: Entity classes, mapped superclasses, and embeddable classes.
- Simple Java data types: Primitive types, wrapper classes, `String`, `Date`, and math types.
- Multi-value types: Collections, maps, and arrays.
- Miscellaneous types: Enum types and serializable types (user-defined or system-defined).
Note: Only instances of entity classes can be stored directly in the database. Other persistable types can be embedded in entity classes as fields. In addition, only entity class instances preserve their identity and are stored only once, even if they are referenced multiple times. Referencing instances of other persistable types from multiple persistent fields causes data duplication in the database.
This page covers the following topics:
Entity classesMapped superclassesEmbeddable classesSimple java data typesDate and time (temporal) typesMulti-value typesProxy ClassesEnum TypesSerializable TypesEntity classes
An entity class is an ordinary user-defined Java class whose instances can be stored in the database. The easiest way to declare a class as an entity is to mark it with the @Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. annotation:
import javax.persistence.Entity; @Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class MyEntity { }
Entity class requirements
A portable JPA entity class:
- Must be a top-level class (that is, not a nested or inner class).
- Must have a
publicorprotectedno-argument constructor. - Must not be
finaland must not havefinalmethods orfinalinstance variables.
ObjectDB is slightly less restrictive:
- Static nested entity classes are allowed, but non-static inner classes are not.
- Instance (non-static) variables cannot be `final`, but classes and methods can be.
- In most cases, ObjectDB can manage a missing no-argument constructor.
Aside from these constraints, an entity class is like any other Java class. It can extend 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 modifier (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 (that is, the short class name without the package name). A different entity name can be set explicitly by using the namejakarta.persistence.Entity.name(Optional) The entity name. attribute of the @Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. annotation:
@Entityjakarta.persistence.EntityDeclares that the annotated class is an entity.(namejakarta.persistence.Entity.name(Optional) The entity name.="MyName") public class MyEntity { }
Entity names must be unique. When two entity classes in different packages share the same class name, explicitly setting the entity name is required to avoid conflicts.
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 it treats mapped superclasses as ordinary entity classes.
Mapped superclasses are useful only in applications that use an ORM-based JPA provider, such as Hibernate, TopLink, EclipseLink, OpenJPA, or DataNucleus.
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 be stored in the database only as embedded objects, that is, as part of a containing entity.
A class is declared as embeddable by marking it with the @Embeddablejakarta.persistence.EmbeddableDeclares a type whose instances are stored as an intrinsic part of an owning entity, sharing the identity of the entity. annotation:
@Embeddablejakarta.persistence.EmbeddableDeclares a type whose instances are stored as an intrinsic part of an owning entity, sharing the identity of the entity. public class Address { String street; String city; String state; String country; String zip; }
Instances of embeddable classes are always embedded in other entities and do not require separate space allocation or separate store and retrieval operations. Therefore, using embeddable classes can save space in the database and improve efficiency.
However, embeddable classes do not have an identity (primary key) of their own. This leads to some limitations (for example, their instances cannot be shared by different entities, and they cannot be queried directly). Therefore, the decision to declare a class as an entity or embeddable requires case-by-case consideration.
Simple java data types
The following simple Java data types are persistable:
- Primitive types:
boolean,byte,short,char,int,long,floatanddouble. - Equivalent wrapper classes from package java.lang:
,
BooleanByte,Short,Character,Integer,Long,FloatandDouble. java.math.BigInteger,java.math.BigDecimal.java.lang.String.java.util.Date,java.util.Calendar,,
java.sql.Datejava.sql.Time,java.sql.Timestamp,java.time.LocalDate,java.time.LocalTime,java.time.LocalDateTime,java.time.OffsetTime,java.time.OffsetDateTime,java.time.Instant.
Date and time types are discussed in more detail in the next section.
Date and time (temporal) types
The java.sql date and time classes represent different parts of dates and times:
java.sql.Date- represents the date only (for example, `2019-12-31`).java.sql.Time- represents the time only (for example, `23:59:59`).java.sql.Timestamp- represents both date and time (for example, `2019-12-31 23:59:59`).
The java.util.Date and ` and `java.util.Calendar` types, on the other hand, are generic and can represent any of the above by using the JPA @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar . annotation:
@Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class DatesAndTimes { // Date Only: java.sql.Date date1; @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..DATEjakarta.persistence.TemporalType.DATEMap as java.sql.Date ) java.util.Date date2 @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..DATEjakarta.persistence.TemporalType.DATEMap as java.sql.Date ) java.util.Calendar date3; // Time Only: java.sql.Time time1; @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..TIMEjakarta.persistence.TemporalType.TIMEMap as java.sql.Time ) java.util.Date time2; @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..TIMEjakarta.persistence.TemporalType.TIMEMap as java.sql.Time ) java.util.Calendar time3; // Date and Time: java.sql.Timestamp dateAndTime1; @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..TIMESTAMPjakarta.persistence.TemporalType.TIMESTAMPMap as java.sql.Timestamp ) java.util.Date dateAndTime2; @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..TIMESTAMPjakarta.persistence.TemporalType.TIMESTAMPMap as java.sql.Timestamp ) 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 dates without the time part, either by using the java.sql.Date type or by specifying the @Temporaljakarta.persistence.TemporalThis annotation must be specified for persistent fields or properties of type Date and Calendar .(TemporalTypejakarta.persistence.TemporalTypeType used to indicate a specific mapping of Date or Calendar ..DATEjakarta.persistence.TemporalType.DATEMap as java.sql.Date ) annotation, has several benefits:
- Saves space in the database.
- Improves efficiency (faster storage and retrieval).
- Simplifies queries on dates and date ranges.
When an entity is stored, its date and time fields are automatically adjusted to the requested mode. For example, the date1, date2, and date3 fields above might be initialized with new Date(), which contains both date and time. The time part is discarded when the entity is stored in the database.
Multi-value types
The following multi-value types are persistable:
- Collection types from the java.util package:
ArrayList,Vector,Stack,LinkedList,ArrayDeque,PriorityQueue,HashSet,LinkedHashSet, andTreeSet. - Map types from
the java.utilpackage:HashMap, Hashtable, WeakHashMap, IdentityHashMap,LinkedHashMap,TreeMap, andProperties. - Arrays, including multi-dimensional arrays.
Both generic (for example, `ArrayList`) and non-generic (for example, `ArrayList`) collection and map types are supported, as long as their values (that is, elements in collections and arrays, and keys and values in maps) are either `null` 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 you use an unsupported collection or map type, ObjectDB switches to a similar supported type when it retrieves the data 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:
@Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class EntityWithList { private List<String> words = Arrays.asList("not", "ArrayList"); }
When the entity is retrieved from the database, the list is instantiated as an ArrayList. Using an interface (List) for the field type is essential in this case to allow ObjectDB to switch to a supported collection type when the entity is retrieved. JPA requires that you declare persistent collection and map fields only as interface types (such as java.util.Collection, java.util.List, java.util.Set, or java.util.Map), and this is also a good practice when you work with ObjectDB.
Proxy Classes
When entities are retrieved from the database, instances of mutable persistable system types (that is, collections, maps, and dates) are instantiated by using proxy classes. These proxy classes extend the original classes and enable transparent activation and 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. You can notice the difference in the debugger view and when invoking the getClass method on an object of a proxy class.
Enum Types
Every enum type (user-defined or system-defined) is persistable. However, if future portability to other platforms is important, you should persist only values of user-defined enum types.
By default, enum values are represented internally by their ordinal numbers. Use caution when modifying an enum type that is already in use in an existing database. You can safely add new enum constants only at the end of the list, which gives them new, higher ordinal numbers.
Alternatively, enum values can be represented internally by their names. In that case, the names must not be changed, because renaming a constant can cause data loss in existing databases.
The @Enumeratedjakarta.persistence.EnumeratedSpecifies that a persistent property or field should be persisted as an enumerated type. annotation enables you to choose the internal representation:
@Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class Style { Color color1; // default is EnumType.ORDINAL @Enumeratedjakarta.persistence.EnumeratedSpecifies that a persistent property or field should be persisted as an enumerated type.(EnumTypejakarta.persistence.EnumTypeEnumerates available options for mapping enumerated types..ORDINALjakarta.persistence.EnumType.ORDINALPersist enumerated type property or field as an integer.) Color color2; @Enumeratedjakarta.persistence.EnumeratedSpecifies that a persistent property or field should be persisted as an enumerated type.(EnumTypejakarta.persistence.EnumTypeEnumerates available options for mapping enumerated types..STRINGjakarta.persistence.EnumType.STRINGPersist enumerated type property or field as a string.) Color color3; } enum Color { RED, GREEN, BLUE };
In the example above, values of the color1 and color2 fields are stored as ordinal numbers (0, 1, and 2), while values of the color3 field are stored as strings ("RED", "GREEN", and "BLUE").
Serializable Types
Every serializable class (user-defined or system-defined) is also persistable. However, relying on serialization to persist data has a severe drawback: lack of portability. The internal Java serialization format will be inaccessible to future versions of ObjectDB on other platforms. Therefore, we recommend that you use only the explicitly specified persistable types.
Serialization is disabled by default
.