<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

# Using custom codecs

The mapper can take advantage of [custom codecs](../../custom_codecs/)
to apply custom conversions to mapped columns and fields.

## Declaring codecs

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:

```java
public class MyCustomDate { ... }

public class MyCustomDateCodec extends TypeCodec<MyCustomDate> {
    public MyCustomDate() {
        super(DataType.timestamp(), MyCustomDate.class);
    }
    ...
}
```

### Pre-registered codecs

If you register your codec with the mapper's underlying `Cluster`, it
will be automatically available to the mapper:

```java
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:

```java
@Table(name = "user")
public class User {
  @PartitionKey
  private int id;
  private MyCustomDate birth;

  ... // getters and setters
}
```

This also works in accessors:

```java
@Accessor
interface UserAccessor {
  @Query("update user set birth = :b where id = :i")
  void updateBirth(@Param("i") int id,
                   @Param("b") MyCustomDate birth);
}
```

### One-time declaration

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`:

```java
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][column]
annotation:

```java
@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][field] and [@Param][param] annotations.

[column]:https://docs.datastax.com/en/drivers/java/3.11/com/datastax/driver/mapping/annotations/Column.html
[field]:https://docs.datastax.com/en/drivers/java/3.11/com/datastax/driver/mapping/annotations/Field.html
[param]:https://docs.datastax.com/en/drivers/java/3.11/com/datastax/driver/mapping/annotations/Param.html


## Implicit UDT codecs

The mapper uses custom codecs internally to handle UDT conversions: when
you register an [entity](../using/#entity-mappers), the mapper inspects
the type of all fields to find classes annotated with
[@UDT](../creating/#mapping-user-types) (this works recursively with
nested UDTs and collections). For each class, the mapper creates a codec
and registers it with the underlying `Cluster`.

```java
@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:

```java
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:

```java
mappingManager.udtCodec(Address.class);

// Codec is now registered
```
