Why domain model mapping?
Many frameworks which deal with user domain model (aka data model) use some kind of
mapping.
For example JPA uses annotations in order to map user classes into relational database.
Plenty of XML and JSON serializers uses various approaches to mapping, usually based on annotations.
When combined together, all of those framework-specific annotations could be a pain and
pollution in Your business domain code.
Mapping is also a case in JaVers but don't worry:
- It's far more simple than JPA
- Javers uses reasonable defaults and take advantage of type inferring algorithm.
So for a quick start just let it do the mapping for You.
Later on, it would be advisable to refine it to optimize diff semantics
- We believe that domain model classes should be framework agnostic,
so we do not ask You to embrace another annotation set
JaVers wants to know only a few basic facts about your domain model classes,
particularly Javers Type of each class spotted in runtime.
Proper mapping is essential for diff algorithm, for example we need to know if objects of given class
should be compared property-by-property or using equals().
Javers Types
We use
Entity and
Value Objects notions following Eric Evans
Domain Driven Design terminology (DDD).
Furthermore, we use
Values,
Primitives and
Containers.
The last two types are internals and can't be mapped by user.
To make long story short, You as a user are asked to label your domain model classes as
Entities, Value Objects or Values.
Do achieve this, use
JaversBuilder
methods:
Entity
JaVers
Entity
has exactly the same semantic like DDD Entity or JPA Entity.
Usually, each entity instance represents concrete physical object.
Entity has a list of mutable properties and its own identity hold in id property.
For example Entities are: Person, Company.
Value Object
JaVers
ValueObject
is similar to DDD ValueObject and JPA Embeddable.
It's a complex value holder with a list of mutable properties but no unique identifier.
In strict DDD approach, Value Objects can't exists independently and have to be bound do Entity instances
(as a part of an Aggregate). Javers is not such radical and supports both embedded and dangling Value Objects.
For example Value Objects are: Address, Point
Value
JaVers
ValueType
is a simple (scalar) value holder.
Two Values are compared using equals() so
its highly important to implement it properly by comparing underlying state.
For example Values are: BigDecimal, LocalDate
For Values it's advisable to customize JSON serialization by implementing Type Adapters, see
JsonConverter
.
TypeMapper and type inferring policy
Javers use lazy approach to type mapping so types are resolved only for classes spotted in runtime.
To show You how it works, assume that Javers is calculating diff on two graphs of objects
and currently two Person.class instances are compared.
ObjectGraphBuilder
asks
TypeMapper
about
JaversType
of Person.class.
TypeMapper
does the following
- If Person.class was spotted before in the graphs, TypeMapper has exact mapping for it and just returns already known JaversType
- If this is a first question about Person.class, TypeMapper checks if it was registered in
JaversBuilder
as one of Entitiy, Value Object or Value. If so, answer is easy.
- Then TypeMapper tries to find so called Prototype—nearest class or interface that is already mapped and is assignable from Person.class.
So as You can see, it's easy to map whole bunch of classes with common superclass or interface with one call to
JaversBuilder
.
Just register those high level concepts.
- When Prototype is not found, Javers tries to infer Type by looking for well known JPA annotations:
javax.persistence.Entity
and javax.persistence.Id
.
If found, class would be mapped as Entity
, otherwise as ValueObject
.
To summarize, identify Entities and Value Objects and Values in your domain model.
Try to distinct them by high level abstract classes, interfaces or JPA annotations.
Minimize your
JaversBuilder
configuration by taking advantage of type inferring policy.
For Values, remember about implementing equals() and consider implementing JSON type adapters.