-
Notifications
You must be signed in to change notification settings - Fork 354
Entity persister
Astyanax provides entity persister APIs that is similar to Java Persistence API (JPA). Please check out "com.netflix.astyanax.entitystore" package.
- we uses annotations from javax.persistence package
- entity class must be annotated with @Entity
- field with @Id annotation will be written as rowKey in cassandra data model. If the same field can also have @Column annotation, then it will also be written as a column redundantly.
- column name cannot contain dot (.) char, which is reserved separator for nested structure
- duplication check for column name is done as case insensitive.
Here is sample code snippet from DefaultEntityManagerTest.java
final String id = "foo";
final SampleEntity origEntity = createRandomEntity(id);
final EntityManager<SampleEntity, String> entityManager =
new DefaultEntityManager.Builder<SampleEntity, String>()
.withEntityType(SampleEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
entityManager.put(origEntity);
SampleEntity getEntity = entityManager.get(id);
entityManager.delete(id);
Here are the ways to specify TTL (lower priority first)
- @TTL annotation at entity class level
@Entity
@TTL(3600) // 1 hour
public class FooEntity {
// your class definition
}
- DefaultEntityManager Builder
EntityManager<FooEntity, String> entityPersister =
new DefaultEntityManager.Builder<FooEntity, String>()
.withEntityType(FooEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(columnFamily)
.withTTL(3600) // 1 hour
.build();
- @TTL annotation at entity method level. this the most flexible and dynamic way of deriving TTL value
@Entity
public class FooEntity {
// it must be zero args and return Integer type
@TTL
public Integer getTTL() {
// your TTL calculation logic
// e.g. you may have entities that are time dependent
// (e.g. flight schedules, subscriptions to services, etc.).
// You can calculate the TTL value (in seconds) to basically
// expire it 1 week after the "end date" of that particular entity
// (which will vary per row/entity).
}
}
- We support nested structure. column name will be concatenated by "." char. That's why dot char is invalid in @Column name annotation.
- Nested type must also be annotated with @Entity just like the root type. But the difference is that nested type doesn't need @Id field/annotation.
- Nesting can be any arbitrary level deep.
Here is the code snippet from SampleEntity.java. When SampleEntity is written to cassandra. There will be two columns of "bar.i" and "bar.s".
@Entity
public class SampleEntity {
@Entity
public static class Bar {
@Column(name="i")
public int i;
@Column(name="s")
public String s;
...
}
...
@Column(name="BAR")
private Bar bar;
...
}
By default (without @Serializer annotation), astyanax will automatically infer the Serializer type based on entity field's java type. Here are the following inference types supported by entity persister.
- basic java types (both primitive and wrapper): byte, short, int, long, boolean, float, double
- String, byte[], Date, UUID
If you have a field that requires custom Serializer, you can specify it with the @Serializer annotation. Here is the code snippet from SampleEntity.java
public class SampleEntity {
public static class Foo {
public int i;
public String s;
public Foo(int i, String s) {
this.i = i;
this.s = s;
}
@Override
public String toString() {
try {
JSONObject jsonObj = new JSONObject();
jsonObj.put("i", i);
jsonObj.put("s", s);
return jsonObj.toString();
} catch (JSONException e) {
throw new RuntimeException("failed to construct JSONObject for toString", e);
}
}
public static Foo fromString(String str) {
try {
JSONObject jsonObj = new JSONObject(str);
return new Foo(jsonObj.getInt("i"), jsonObj.getString("s"));
} catch (JSONException e) {
throw new RuntimeException("failed to construct JSONObject for toString", e);
}
}
...
}
public static class FooSerializer extends AbstractSerializer<Foo> {
private static final String UTF_8 = "UTF-8";
private static final Charset charset = Charset.forName(UTF_8);
private static final FooSerializer instance = new FooSerializer();
public static FooSerializer get() {
return instance;
}
@Override
public ByteBuffer toByteBuffer(Foo obj) {
if (obj == null) {
return null;
}
return ByteBuffer.wrap(obj.toString().getBytes(charset));
}
@Override
public Foo fromByteBuffer(ByteBuffer byteBuffer) {
if (byteBuffer == null) {
return null;
}
return Foo.fromString(charset.decode(byteBuffer).toString());
}
...
}
@Column(name="FOO")
@Serializer(FooSerializer.class)
private Foo foo;
...
}
A Netflix Original Production
Tech Blog | Twitter @NetflixOSS | Jobs
- Getting-Started
- Configuration
- Features
- Monitoring
- Thread Safety
- Timeouts
- Recipes
- Examples
- Javadoc
- Utilities
- Cassandra-Compatibility
- FAQ
- End-to-End Examples
- Astyanax Integration with Java Driver