evitaDB - Fast e-commerce database
logo
page-background

Associated data implicit conversion process

Related data represents complex unstructured or semi-structured documents that can be automatically converted from/to Java POJO classes automatically using implicit conversion mechanisms.

The complex types are all types that don't qualify as simple evitaDB types (or an array of simple evitaDB types) and don't belong to a java package (i.e. java.lang.URL is forbidden to be stored in evitaDB, even if it is Serializable, because is in the package java, and is not directly supported by the basic data types). The complex types are targeted for the client POJO classes to carry bigger data or associate simple logic along with the data.
Associated data may even contain array of POJOs. Such data will be automatically converted to an array of ComplexDataObject types - i.e. ComplexDataObject[].

The complex type can contain the properties of:

Collection generics must be resolvable to an exact class (meaning that wildcard generics are not supported). The complex type may also be an immutable class, accepting properties via the constructor parameters. Immutable classes must be compiled with the javac -parameters argument, and their names in the constructor must match their property names of the getter fields. This plays really well with Lombok @Data annotation.

Serialization

Storing a complex type to entity is executed as follows:

All properties that comply with JavaBean naming rules and have both an accessor, a mutator method (i.e. get and set methods for the property) and are not annotated with annotation, are serialized into a complex type. See the following example:
As you can see, annotations can be placed either on methods or property fields, so that if you use Lombok support, you can still easily define the class:
If the serialization process encounters any property that cannot be serialized, the is thrown.

Generic collections

You can use collections in complex types, but the specific collection types must be extractable from the collection generics in deserialization time. Look at the following example:

Because methods that don't follow the JavaBeans contract are silently skipped, it is highly recommended to always store and retrieve associated data in the unit test and check that all important data is actually stored:

Deserialization, model evolution support

Retrieving a complex type from an entity is executed as follows:

Complex types are internally converted to a type, that can be safely stored in evitaDB storage. The (de)serialization process is also designed to prevent data loss, and allow model evolution.

The deserialization process may fail with two exceptions:

  • is raised when certain property cannot be deserialized due to an incompatibility with the specified contract
  • is raised when any of the serialized data was not deserialized due to a lack of a mutator method on the class it's being converted to

Field removal

The exception protects developers from unintentional data loss by making a mistake in the Java model and then executing:
  • a fetch of existing complex type
  • altering a few properties
  • storing it back again to evitaDB
If there is legal reason for dropping some data stored along with its complex type in the previous versions of the application, you can use annotation on any complex type class to declare that it is ok to throw away data during deserialization.
Example:

Associated data were stored with this class definition:

In future versions, developer will decide that the id field is not necessary anymore and may be dropped. But there is a lot of data written by the previous version of the application. So, when dropping a field, we need to make a note for evitaDB that the presence of any id data is ok, even if there is no field for it anymore. This data will be discarded when the associated data gets rewritten by the new version of the class:

Field renaming and controlled migration

There are also situations when you need to rename the field (for example you made a typo in the previous version of the Java Bean type). In such case you'd also experience the when you try to deserialize the type with the corrected Java Bean definition. In this situation, you can use the annotation to migrate old versions of data.
Example:

First version of the Java type with the mistake:

Next time we'll try to fix the typo:

But we make yet another mistake, so we need another correction:

We may get rid of those annotations when we're confident there is no data with the old contents in evitaDB. Annotation can also be used for model evolution - i.e. automatic translation of an old data format to the new one.
Example:

Old model:

New model:

Author: Ing. Jan Novotný

Date updated: 15.12.2022

Documentation Source