Mapping
Classes
Mapping is achieved through one of two annotations to start: @Entity and
@Embedded.
In order for Morphia to consider any type for mapping, it must have one of these two annotation. @Entity
is used to denote a "top level" type.
These types tend to have their own collections whose names can be mapped via the value
parameter.
Leaving this value blank will leave Morphia free to compute the collection name as defined by the collection naming strategy defined in MapperOptions.
That default is currently the camel case value of the class’s simple name.
For example, to map a UserProfile
entity under this strategy, the collection name would be mapped to userProfile
.
Any type annotated with @Entity must have a field annotated with @Id. The type of the field can be any type as long as Morphia, or the driver, has codecs that can map the data to and from mongodb. When mapping an entity, one can also define indexes and schema validations as part of the entity declaration as well.
Constructors
Morphia has traditionally required a 0-argument constructor on any mapped entity. In fact, Morphia still prefers to use such a constructor should one be available. However, as of 2.1, Morphia can also make use another constructor that meets certain criteria
-
The number of arguments in the constructor must match the number of fields on the class. That is, every field must be represented in the constructor signature.
-
The names of the arguments must match the names of the fields. Here, there is a bit of flexibility. The argument name can match either the field name as found in the source or the mapped name as determined by any
@Property
annotation. While this is likely to be the most common case as it is the simplest, for various this won’t always be possible or preferable. If a constructor argument name can’t mirror the field name, using the @Name annotation, an explicit name can be given so that the argument can be properly matched to a field.
Changing the mapping configuration can interfere with Morphia’s ability to map arguments and fields so be careful when making changes to such things as the default field naming strategy or |
For this mapping to take place, the source must be compiled to include the parameters in the generated bytecode.
With javac
this is typically already configured by default.
However, Kotlin users will likely need to configure their builds to include the appropriate option.
For maven users, it’s as simple as adding one line to the Kotlin maven plugin <configuration>
:
<javaParameters>true</javaParameters>
External types
Some times persisted types come from external libraries whose source is either unavailable or simply can’t be modified.
Using these types would be impossible give the annotation requirements as stated above.
Morphia 2.1 introduces a new experimental API that loosens these restrictions a bit.
Using Mapper#mapExternal these external types can be passed
in for use as embedded types in other entities.
An optional instance of @Embedded
can created using the
EmbeddedBuilder.
A null can be passed in to simply accept the default values.
This API is experimental and is likely to shift a bit as it sees usage and feedback from the community. |
Versioning
Entities can be versioned to ensure that changes are applied serially and that no other processes are modifying an object in between the time it’s fetched, modified, and written back to the database.
To achieve this, simply add a field to a type, it can be a long
or a
Long
and annotation that field with @Version.
This field must not be initialized to anything other than zero or null, however.
Morphia will take care of the rest.
If an object is fetched and another process updates the corresponding document in the database before it can be persisted back, an exception will be thrown when the write is attempted.
Fields
By default, any non-static field on a mapped class will be processed for persistence.
If a field is to be excluded from the mapping, it can be decorated with the transient
keyword, annotated with @Transient, or with the java.beans.Transient
annotation.
Otherwise all fields will be included that are defined on the mapped class and any super type.
However, Morphia will ignore fields in any super types found in java*
packages which includes the standard JDK classes and the Java EE APIs.
There are times when it is necessary to modify a field mapping’s name, e.g. Using the
@Property annotation, a new name can be defined that will be used when writing to and reading from the database.
During a schema evolution, it is possible to load a field from an old name as well using the
@AlsoLoad annotation.
Using this annotation, multiple old names can be used to find a field’s value in a returned document from query.
However, only the field’s name or the value specified in the @Property
annotation will be used when writing documents back to the database.
Similarly, if data is only intended to be loaded from the database but never written back, that field can be annotated with @LoadOnly
If you do not specify a name via @Property
, the default field naming strategy will be used.
The default strategy is to use the field’s name as defined in the source.
This strategy can be changed globally via the field naming strategy option on
MapperOptions.
Simple indexes can be defined on a field if all that is needed for the index is a single field.
This can be done via the @Indexed annotation.