Skip to content

Entity persister

georgkoester edited this page Jan 19, 2013 · 28 revisions

Astyanax provides entity persister APIs that is similar to Java Persistence API (JPA). Please check out "com.netflix.astyanax.entitystore" package.

Quick notes

  • 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
  • column name will be normalized to lower cases when writing to cassandra. In another word, column name is case insensitive.
  • TTL: you can set row-level TTL with DefaultEntityManager.Builder. In addition, you can also set per-column TTL with @TTL annotation. However it seems a little weird to have different TTL for different columns. So you might really want to think about per-row TTL setting.

Basic put/get/delete operations

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);

Nested 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;
	...
}

Explicit @Serializer annotation

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;
	...
}
Clone this wiki locally