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[].
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:
Recommended test coverage
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.