-
Notifications
You must be signed in to change notification settings - Fork 92
Achilles Custom Types
Below is a list of all Achilles annotations
- AnalyzerClass
- CassandraShutdownHook
- CassandraVersion
- Codec
- CodecSignature
- ColumnMappingStrategy
- Encoding
- Empty
- IndexMode
- InsertStrategy
- Interceptor
- LWTResultListener
- NamingStrategy
- Normalization
- SchemaNameProvider
- Tuplexxx
- TypedMap
- JSON
- MaterializedView
- PartitionKey
- RuntimeCodec
- SASI
- Static
- Strategy
- TTL
- Table
- TimeUUID
- Transient
- UDT
Analyzer class to be used for SASI support. Possible values are:
- NO_OP_ANALYSER (DEFAULT): do not analyze the input
- NON_TOKENIZING_ANALYZER: only valid for text/ascii data types. Do not tokenize the input. Normalization by lowercase/uppercase is allowed
- STANDARD_ANALYZER: only valid for text/ascii data types. Split the input text into tokens, using the locale defined by attribute 'locale' Normalization by lowercase/uppercase is allowed
Shutdown hook to control when to shutdown the embedded Cassandra process.
CassandraShutDownHook shutdownHook = new CassandraShutDownHook();
Session session = CassandraEmbeddedServerBuilder.builder()
.withShutdownHook(shutdownHook)
...
.buildNativeSession();
...
shutdownHook.shutdownNow();
Please note that upon call on shutdownNow()
, Achilles will trigger the shutdown of:
- the embedded Cassandra server
- the associated Cluster object
- the associated Session object
This is an enum used to declare the Cassandra version you're using for compile to configure Achilles at compile time.
@CompileTimeConfig(cassandraVersion = CassandraVersion.CASSANDRA_3_0_X)
public interface AchillesConfig {
}
Depending on the chosen version, Achilles will generate appropriate DSL code.
Define a codec to transform a source type into a target type.
The source type can be any Java type. The target type should be a Java type supported by Cassandra
public interface Codec<FROM, TO> {
Class<FROM> sourceType();
Class<TO> targetType();
TO encode(FROM fromJava) throws AchillesTranscodingException;
FROM decode(TO fromCassandra) throws AchillesTranscodingException;
}
Example of LongToString codec:
public class LongToString implements Codec<Long,String> {
@Override
public Class<Long> sourceType() {
return Long.class;
}
@Override
public Class<String> targetType() {
return String.class;
}
@Override
public String encode(Long fromJava) throws AchillesTranscodingException {
return fromJava.toString();
}
@Override
public Long decode(String fromCassandra) throws AchillesTranscodingException {
return Long.parseLong(fromCassandra);
}
}
Utility class to identify uniquely a codec. A codec signature is composed of:
- sourceType
- targetType
- optionally, codecName if provided
See Runtime Codec for more details
You can specify the column mapping strategy at compile time using the @CompileTimeConfig
annotation:
@CompileTimeConfig(cassandraVersion = CassandraVersion.CASSANDRA_3_0_X, columnMappingStrategy = ColumnMappingStrategy.IMPLICIT)
public interface AchillesConfig {
}
The default behavior is ColumnMappingStrategy.EXPLICIT
See Column Mapping Strategy for more details
Define the encoding type for enum values. 2 choices are available:
-
info.archinnov.achilles.annotations.Enumerated.Encoding.NAME
encode enum using theirname()
-
info.archinnov.achilles.annotations.Enumerated.Encoding.ORDINAL
encode enum using theirordinal()
More details on Enum type
It is just a marker enum for asynchronous operations. Sometimes an operation does not return any meaningful result
(like deleteById(...)
or insert(...)
).
Still we need to be able to ensure that the asynchronous operation has been executed correctly by calling get()
.
If the execution has been successful, the singleton Empty
is returned, otherwise an exception is raised
For more details, please check Asynchronous Operations
Indexing mode for SASI. Possible values are:
- PREFIX (DEFAULT): allows search on prefix for text/ascii data types. Default and only valid index mode for non-text data types
- CONTAINS: allows search on prefix, suffix and substring for text/ascii data types. Invalid for non-text data types
- SPARSE: only valid for non-text data types. SPARSE mode is optimized for low-cardinality e.g. for indexed values having 5 or less corresponding rows. If there are more than 5 CQL rows having this index value, SASI will complain by throwing an exception
Define the insert strategy on an entity. Right now only 2 values are possible:
info.archinnov.achilles.type.InsertStrategy.NOT_NULL_FIELDS
info.archinnov.achilles.type.InsertStrategy.ALL_FIELDS
Upon call to insert()
, depending on the chosen strategy Achilles will
- insert all fields on the entity, even if they are null
- insert only non null fields of the entity
Check here for more details on the Insert strategy
This is an interface defining the contract for a lifecycle interceptor. For more details, please check Interceptors
public interface Interceptor<T>
{
boolean acceptEntity(Class<?> entityClass);
public void onEvent(T entity);
public List<Event> events();
}
For all LWT operations, Cassandra returns an [applied]
boolean column telling whether the operation has been successful or not. If a LWT update operation failed, Cassandra also returns the current values that differ from the ones used by the LWT update.
To intercepts the LWT operation result and current values, you can register a LWTResultListener
using the Options
API (see above)
The signature of the LWTResultListener
is:
public interface LWTResultListener {
default void onSuccess() {
// Do nothing
}
void onError(LWTResult lwtResult);
}
The LWTResult
type is defined as:
public class LWTResult {
private final Operation operation;
private final TypedMap currentValues;
public LWTResult(Operation operation, TypedMap currentValues) {
this.operation = operation;
this.currentValues = currentValues;
}
...
public static enum Operation {INSERT, UPDATE}
}
For more details on LWT operations, please refer to Lightweight Transaction
Define the naming strategy for the keyspace, table and column name. There are 3 possible strategies:
- SNAKE_CASE: transform all schema name using snake case
- CASE_SENSITIVE: enclose the name between double quotes (") for escaping the case
- LOWER_CASE: transform the name to lower case
Check here for more details on the Naming strategy
Text normalization mode for SASI. Possible values are:
- NONE (DEFAULT): no normalization
- LOWERCASE: normalize input text and search term to lower case
- UPPERCASE: normalize input text and search term to upper case
This is an interface to be implemented to provide dynamic binding of keyspace/table name at runtime. The interface is
public interface SchemaNameProvider {
/**
* Provide keyspace name for entity class
*/
<T> String keyspaceFor(Class<T> entityClass);
/**
* Provide table name for entity class
*/
<T> String tableNameFor(Class<T> entityClass);
}
The provider can be used with CRUD API and DSL API
Since Cassandra supports tuple type and the Java driver only exposes a com.datastax.driver.core.TupleValue
,
Achilles introduces Tuple1
, Tuple2
, ..., Tuple10
types. They all extends the Tuple
interface
and exposes the following methods:
//Get all tuple values, in the correct order
public List<Object> values();
//Return the 1st component of the tuple
public A _1();
//Return the 2nd component of the tuple
public B _2();
...
//Return the 10th component of the tuple
public J _10();
Internally, Achilles will perform automatic conversion between those tuple types to/from
com.datastax.driver.core.TupleValue
so that you can use them directly in your entities
@Table
public class Entity {
@Column
private Tuple3<String, List<String>, Long> tuple3;
...
}
Note: in the above example, there is no need to add
@Frozen
on theList<String>
because all tuples are frozen by default.
The native query API used to return a Map<String,Object>
as result. It is not very user-friendly because it forces you do manual type casting. Example:
Map<String,Object> columns = manager.nativeQuery("SELECT * FROM users WHERE userId = 10").getFirst();
String name = (String)columns.get("name"); // BAD !
Long age = (Long)columns.get("age"); // BAD !
TypedMap
is just an extension of Map<String,Object>
offering two extras methods for convenience:
@SuppressWarnings("unchecked")
public <T> T getTyped(String key) {
T value = null;
if (super.containsKey(key) && super.get(key) != null) {
value = (T) super.get(key);
return value;
}
return value;
}
public <T> T getTypedOr(String key, T defaultValue) {
if (super.containsKey(key)) {
return getTyped(key);
} else {
return defaultValue;
}
}
Of course there is no magic, the dirty casting you no longer do, getTyped()
will do it for you. The target type is passed at runtime while calling the method. getTypedOr()
lets you provide a fall-back value.
Example of usage:
TypedMap columns = manager.nativeQuery("SELECT * FROM users WHERE userId = 10").first();
// Explicit type (String) is passed to method invocation
String name = columns.<String>getTyped("name");
// No need to provide explicit type. The compiler will infer type in this case
Long age = columns.get("age");
-
Bootstraping Achilles at runtime
- Runtime Configuration Parameters
-
Manager
-
Consistency Level
-
Cassandra Options at runtime
-
Lightweight Transaction (LWT)
-
JSON Serialization
-
Interceptors
-
Bean Validation (JSR-303)