The mapper can take advantage of custom codecs to apply custom conversions to mapped columns and fields.
Let's assume you have a table containing a timestamp column:
create table user(id int primary key, birth timestamp);
You've created a custom class, and the codec to convert it:
public class MyCustomDate { ... } public class MyCustomDateCodec extends TypeCodec<MyCustomDate> { public MyCustomDate() { super(DataType.timestamp(), MyCustomDate.class); } ... }
If you register your codec with the mapper's underlying Cluster
, it will be automatically available to the mapper:
Cluster cluster = Cluster.builder() .addContactPoint("127.0.0.1") .withCodecRegistry( new CodecRegistry().register(new MyCustomDateCodec()) ).build(); MappingManager mappingManager = new MappingManager(cluster.connect());
You can normally create your mapped classes using your custom type, without any additional configuration:
@Table(name = "user") public class User { @PartitionKey private int id; private MyCustomDate birth; ... // getters and setters }
This also works in accessors:
@Accessor interface UserAccessor { @Query("update user set birth = :b where id = :i) void updateBirth(@Param("i") int id, @Param("b") MyCustomDate birth); }
Sometimes you might want to use your codec only for one particular column/field. In that case you won't register it when initializing the Cluster
:
Cluster cluster = Cluster.builder() .addContactPoint("127.0.0.1") .build(); MappingManager mappingManager = new MappingManager(cluster.connect());
Instead, reference the codec's class in the @Column annotation:
@Table(name = "user") public class User { @PartitionKey private int id; @Column(codec = MyCustomDateCodec.class) private MyCustomDate birth; ... // getters and setters }
The class must have a no-arg constructor. The mapper will create an instance (one per column) and cache it for future use.
This also works with @Field and @Param annotations.
The mapper uses custom codecs internally to handle UDT conversions: when you register an entity, the mapper inspects the type of all fields to find classes annotated with @UDT (this works recursively with nested UDTs and collections). For each class, the mapper creates a codec and registers it with the underlying Cluster
.
@UDT(name = "address") public class Address { ... } @Entity(name = "user") public class User { ... private Address address; ... } Mapper<User> userMapper = mappingManager.mapper(User.class); // Codec is now registered for Address <-> CQL address
A nice side-effect is that you can now use the @UDT
-annotated class with any driver method, not just mapper methods:
Row row = session.execute("select address from user where id = 1").one(); Address address = row.get("address", Address.class);
If you don't use entity mappers but still want the convenience of the UDT codec for core driver methods, the mapper provides a way to create it independently:
mappingManager.udtCodec(Address.class); // Codec is now registered