mapper能夠利用自定義編解碼器將自定義轉換映射到 columns和fields.html
假定有一張表,含有timestamp column:java
create table user(id int primary key, birth timestamp);
還create了一個custom class, 一個codec 來 vonvert it:git
public class MyCustomDate { ... } public class MyCustomDateCodec extends TypeCodec<MyCustomDate> { public MyCustomDate() { super(DataType.timestamp(), MyCustomDate.class); } ... }
若是你register codec with the mapper's underlying Cluster
, it will be automatically available to the mapper:github
Cluster cluster = Cluster.builder() .addContactPoint("127.0.0.1") .withCodecRegistry( new CodecRegistry().register(new MyCustomDateCodec()) ).build(); MappingManager mappingManager = new MappingManager(cluster.connect());
你能夠正常的使用自定義的type來 create mapped類, 而不須要額外的配置:json
@Table(name = "user") public class User { @PartitionKey private int id; private MyCustomDate birth; ... // getters and setters }
This also works in accessors:session
@Accessor interface UserAccessor { @Query("update user set birth = :b where id = :i") void updateBirth(@Param("i") int id, @Param("b") MyCustomDate birth); }
有時只須要在指定的column/field上使用codec, Cluster初始化時不須要register:app
Cluster cluster = Cluster.builder() .addContactPoint("127.0.0.1") .build(); MappingManager mappingManager = new MappingManager(cluster.connect());
@Column註解就起到做用了ide
@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.ui
This also works with @Field and @Param annotations.spa
隱式codec
@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
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
////////////////////////////////////分界線, 上面的是使用,下面的是介紹//////////////////////////////////////////////////////////
Custom codecs支持 transparent, user-configurable mapping of CQL types to arbitrary Java objects.
這種特徵的實際用例不少:
序列化機制的中心部分是TypeCodec。
每個TypeCodec支持 Java type和CQL type 雙向映射. 所以TypeCodec可以進行4項基本操做
有這樣一種場景: user有JSON文檔store在varchar column, 他但願driver使用Jackson library自動映射此column 爲Java對象,而不是返回一個原生的JSON string.
簡單的table結構以下
CREATE TABLE t (id int PRIMARY KEY, json VARCHAR);
首先實現一個合適的codec. 使用Jackson, 一個可能的Json codec 以下:
/** * A simple Json codec. */ public class JsonCodec<T> extends TypeCodec<T> { private final ObjectMapper objectMapper = new ObjectMapper(); public JsonCodec(Class<T> javaType) { super(DataType.varchar(), javaType); } @Override public ByteBuffer serialize(T value, ProtocolVersion protocolVersion) throws InvalidTypeException { if (value == null) return null; try { return ByteBuffer.wrap(objectMapper.writeValueAsBytes(value)); } catch (JsonProcessingException e) { throw new InvalidTypeException(e.getMessage(), e); } } @Override @SuppressWarnings("unchecked") public T deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) throws InvalidTypeException { if (bytes == null) return null; try { byte[] b = new byte[bytes.remaining()]; // always duplicate the ByteBuffer instance before consuming it! bytes.duplicate().get(b); return (T) objectMapper.readValue(b, toJacksonJavaType()); } catch (IOException e) { throw new InvalidTypeException(e.getMessage(), e); } } @Override public String format(T value) throws InvalidTypeException { if (value == null) return "NULL"; String json; try { json = objectMapper.writeValueAsString(value); } catch (IOException e) { throw new InvalidTypeException(e.getMessage(), e); } return '\'' + json.replace("\'", "''") + '\''; } @Override @SuppressWarnings("unchecked") public T parse(String value) throws InvalidTypeException { if (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) return null; if (value.charAt(0) != '\'' || value.charAt(value.length() - 1) != '\'') throw new InvalidTypeException("JSON strings must be enclosed by single quotes"); String json = value.substring(1, value.length() - 1).replace("''", "'"); try { return (T) objectMapper.readValue(json, toJacksonJavaType()); } catch (IOException e) { throw new InvalidTypeException(e.getMessage(), e); } } protected JavaType toJacksonJavaType() { return TypeFactory.defaultInstance().constructType(getJavaType().getType()); } }
幾個實施指南:
接下來register你的codec with CodecRegistry實例
JsonCodec<MyPojo> myJsonCodec = new JsonCodec<MyPojo>(MyPojo.class); CodecRegistry myCodecRegistry = cluster.getConfiguration().getCodecRegistry(); myCodecRegistry.register(myJsonCodec);
Cluster
's CodecRegistry 是最簡單的方式, Cluster實例默認使用CodecRegistry.DEFAULT_INSTANCE,對大多數用來講已經夠用.
然而,咱們仍是能夠create一個使用不一樣CodecRegistry的cluster
CodecRegistry myCodecRegistry = new CodecRegistry(); Cluster cluster = new Cluster.builder().withCodecRegistry(myCodecRegistry).build();
Note:新的CodecRegistry,會自動register全部默認的codecs.
Cluster cluster = ... Session session = ... MyPojo myPojo = ... // Using SimpleStatement Statement stmt = new SimpleStatement("INSERT INTO t (id, json) VALUES (?, ?)", 42, myPojo)); // Using the Query Builder BuiltStatement insertStmt = QueryBuilder.insertInto("t") .value("id", 42) .value("json", myPojo); // Using BoundStatements PreparedStatement ps = session.prepare("INSERT INTO t (id, json) VALUES (?, ?)"); BoundStatement bs1 = ps.bind(42, myPojo); // or alternatively... BoundStatement bs2 = ps.bind() .setInt(0, 42) .set(1, myPojo, MyPojo.class);
And here is how to retrieve a MyPojo
object converted from a JSON document:
ResultSet rs = session.execute(...); Row row = rs.one(); // Let the driver convert the string for you... MyPojo myPojo = row.get(1, MyPojo.class); // ... or retrieve the raw string if you need it String json = row.get(1, String.class); // row.getString(1) would have worked too
....
https://github.com/datastax/java-driver/tree/3.x/manual/custom_codecs