Sophie

Sophie

distrib > Mageia > 7 > i586 > media > core-release > by-pkgid > 91bb7aae0d75a473c7417d2d08339482 > files > 42

cassandra-java-driver-3.4.0-1.mga7.noarch.rpm

## Definition of mapped classes

The object mapper is configured by annotations on the mapped classes.

### Creating a table entity

A table entity is a class that will be mapped to a table in Cassandra.
It is annotated with [@Table][table]:

```
CREATE TABLE user (user_id uuid PRIMARY KEY, name text);
```

```java
@Table(keyspace = "ks", name = "users",
       readConsistency = "QUORUM",
       writeConsistency = "QUORUM",
       caseSensitiveKeyspace = false,
       caseSensitiveTable = false)
public class User {
    @PartitionKey
    @Column(name = "user_id")
    private UUID userId;
    private String name;
    // ... constructors / getters / setters
}
```

`@Table` takes the following options:

- `keyspace`: the keyspace for the table.
- `name`: the name of the table in the database.
- `caseSensitiveKeyspace`: whether the keyspace name is [case-sensitive].
- `caseSensitiveTable`: whether the table name is [case-sensitive].
- `readConsistency`: the [consistency level] that will be used on each
  get operation in the mapper. (if unspecified, it defaults to the
  cluster-wide setting)
- `writeConsistency`: the [consistency level] that will be used on each
  save, or delete operation in the mapper. (if unspecified, it defaults
  to the cluster-wide setting)

The class must provide a default constructor. The default constructor
is allowed to be non-public, provided that the security manager, if any, grants
the mapper access to it via [reflection][set-accessible].

#### Mapping table columns

The mapping of each table column can be customized through annotations 
placed on either a field declaration, or on a getter method of a 
[Java bean property][java-beans]. _Annotations on setters are not 
supported and will be silently ignored by the mapper_. 

Users are strongly encouraged to follow the Java bean property 
conventions when designing mapped classes: if this is the case, the mapper will
transparently "bind" together fields and accessor methods (getters and setters)
into a single logical abstraction; e.g. a field named `myCol` and a Java
bean property named `myCol` offering a public getter named `getMyCol()`
will be assumed to represent the very same table column,
and annotations for this column are thus allowed to be placed indifferently
on the field declaration, or on the getter method declaration.

The following mappings are thus equivalent:

```java
@Table(name = "users")
public class User {

    // annotation on a field
    @PartitionKey
    private UUID id;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

}
```

```java
@Table(name = "users")
public class User {

    private UUID id;

    // annotation on a getter method
    @PartitionKey
    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

}

```

It is recommended to adopt one strategy or the other for
placing annotations on class members (i.e., either always on fields, or always on getters), 
but not both at the same time, unless strictly required.
Annotating fields is usually less verbose, but with polymorphic
data models (see below), annotating getters generally proves to be more flexible.

If duplicated annotations for a given column are found on the field declaration
and on the getter method declaration, the one declared in the getter method
declaration wins. No warnings are generated in such situations.

When reading or writing mapped property values, the mapper will first
try to invoke the property getter and setter methods, if they are available;
and if they are not, the mapper will try a direct access to the property's corresponding field.

A mapped field is thus allowed to be non-public if:

1. Reads and writes are done through its public getters and setters; or
2. The security manager, if any, grants the mapper access to it via [reflection][set-accessible].

Note that, according to the [Java Beans specification][java-beans], a setter
must have a `void` return type; the driver, however, will consider as a setter any public method
having a matching signature (i.e., name and parameter types match those expected),
but having a different return type. This allows the usage of "fluent" setters that can
be chained together in a builder-pattern style:

```java
@Table(name = "users")
public class User {

    // fluent setters
    
    public User setId(UUID id) {
        this.id = id;
        return this;
    }

    public User setName(String name) {
        this.name = name;
        return this;
    }

}

// chained calls
User user = new User()
    .setId(UUIDs.random())
    .setName("John Doe");
```

[table]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Table.html
[case-sensitive]:http://docs.datastax.com/en/cql/3.3/cql/cql_reference/ucase-lcase_r.html
[consistency level]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/core/ConsistencyLevel.html
[java-beans]:https://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html
[set-accessible]:https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

#### Column names

By default, the mapper tries to map each Java bean property to a
column of the same name. _The mapping is case-insensitive by default_,
i.e., the property `userId` would map to a column named `userid`.

If you want to use a different name, or [case-sensitive] names, 
use the [@Column][column] annotation.

To specify a different column name, use the `name` attribute:

```
CREATE TABLE users(id uuid PRIMARY KEY, user_name text);
```

```java
// column name does not match field name
@Column(name = "user_name")
private String userName;
```

When case-sensitive identifiers are required, use the
`caseSensitive` attribute:

```
CREATE TABLE users(id uuid PRIMARY KEY, "userName" text);
```

```java
// column name is case-sensitive
@Column(caseSensitive = true)
private String userName;
```

[column]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Column.html

#### Primary key fields

[@PartitionKey][pk] and [@ClusteringColumn][cc] are used to indicate the
[partition key][pks] and [clustering columns][pks]. In the case of a
composite partition key or multiple clustering columns, the integer
value indicates the position of the column in the key:

```
CREATE TABLE sales(countryCode text, areaCode text, sales int,
                   PRIMARY KEY((countryCode, areaCode)));
```

```java
@PartitionKey(0)
private String countryCode;
@PartitionKey(1)
private String areaCode;
```

The order of the indices must match that of the columns in the table
declaration.

[pk]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/PartitionKey.html
[cc]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/ClusteringColumn.html
[pks]:http://thelastpickle.com/blog/2013/01/11/primary-keys-in-cql.html

#### Computed fields

[@Computed][computed] can be used on properties that are the result of a
computation on the Cassandra side, typically a function call. Native
functions in Cassandra like `writetime()` or [User Defined Functions] are
supported.

```java
@Computed("ttl(name)")
Integer ttl;
```

The CQL return type of function must match the type of the property,
otherwise an exception will be thrown.

Computed fields are ignored when saving an entity.

`@Computed` does not support case-sensitivity. If the expression
contains case-sensitive column or function names, you'll have to escape
them:

```java
@Computed("\"myFunction\"(\"myColumn\")")
int f;
```

Finally, computed properties are only supported with [basic read
operations](../using/#basic-crud-operations) at this time.
Support in [accessors](../using/#accessors) is planned for a future
version (see
[JAVA-832](https://datastax-oss.atlassian.net/browse/JAVA-832)).

[User Defined Functions]:http://www.planetcassandra.org/blog/user-defined-functions-in-cassandra-3-0/
[computed]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Computed.html

#### Transient properties

By default, the mapper will try to map all fields and Java bean properties
to table columns. [@Transient][transient] can be used to prevent a field or 
a Java bean property from being mapped. Like other column-level annotations, 
it should be placed on either the field declaration or the property getter method.

[transient]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Transient.html

### Mapping User Types

[User Defined Types] can also be mapped by using [@UDT][udt]:

```
CREATE TYPE address (street text, zip_code int);
```

```java
@UDT(keyspace = "ks", name = "address")
class Address {
    private String street;
    @Field(name = "zip_code")
    private int zipCode;
    // ... constructors / getters / setters
}
```

`@UDT` takes the following options:

- `keyspace`: the keyspace for the UDT.
- `name`: the name of the UDT in the database.
- `caseSensitiveKeyspace`: whether the keyspace name is case-sensitive.
- `caseSensitiveType`: whether the UDT name is case-sensitive.

The class must provide a default constructor. The default constructor
is allowed to be non-public, provided that the security manager, if any, grants
the mapper access to it via [reflection][set-accessible].

As for table entities, properties in UDT classes are mapped to an UDT field of the same
name by default.

To declare a different name or use case-sensitivity,
use the [@Field][field] annotation:

```java
@Field(name = "zip_code")
private int zipCode;
```

When a table has a UDT column, the mapper will automatically map it to
the corresponding class:

```
CREATE TABLE company (company_id uuid PRIMARY KEY, name text, address address);
```

```java
public class Company {
    @PartitionKey
    @Column(name = "company_id")
    private UUID companyId;
    private String name;
    private Address address;
}
```

This also works with UDTs inside collections or other UDTs, with any arbitrary
nesting level.

[User Defined Types]: ../../udts/
[udt]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/UDT.html
[field]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Field.html

### Mapping collections

Java collections will be automatically mapped into corresponding
Cassandra types. As in Cassandra, collections can contain all native
types and all [user types](#mapping-user-types) previously defined is
the database.

Collection and UDT fields should be annotated to indicate whether they are
frozen. Currently this is only for informational purposes (the mapper
won't check that the declarations match the rules in Cassandra).
However it is a good idea to keep using these annotations and make sure
they match the schema, in anticipation for the schema generation features
that will be added in a future version.
The default annotation is [@Frozen][frozen], [@FrozenKey][frozenkey] and
[@FrozenValue][frozenvalue] are also provided for convenience:

```java
// Will be mapped as a 'list<text>'
private List<String> stringList;

// Will be mapped as a 'frozen<list<text>>'
@Frozen
private List<String> frozenStringList;

// Will be mapped as 'map<frozen<address>, frozen<list<text>>>'
@FrozenKey
@FrozenValue
private Map<Address, List<String>> frozenKeyValueMap;

// Will be mapped as 'map<text, frozen<list<address>>>'
@FrozenValue
private Map<String, List<Address>> frozenValueMap;
```

[frozen]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/Frozen.html
[frozenkey]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/FrozenKey.html
[frozenvalue]:http://docs.datastax.com/en/drivers/java/3.4/com/datastax/driver/mapping/annotations/FrozenValue.html


### Polymorphism support

When mapping an entity class or a UDT class, the mapper will transparently
scan superclasses and superinterfaces for annotations on fields and getter methods,
thus enabling the polymorphic mapping of one class hierarchy
into different CQL tables or UDTs.

Each concrete class must correspond to a table or a UDT,
and should be annotated accordingly with `@Table` or `@UDT`. 
This is analogous to the so-called "table per concrete class" 
mapping strategy usually found in popular SQL mapping frameworks, such as Hibernate.

Here is an example of a polymorphic mapping:

```sql
CREATE TYPE point2d (x int, y int);
CREATE TYPE point3d (x int, y int, z int);
CREATE TABLE rectangles (id uuid PRIMARY KEY, bottom_left frozen<point2d>, top_right frozen<point2d>);
CREATE TABLE spheres (id uuid PRIMARY KEY, center frozen<point3d>, radius double);
```

```java
@UDT(name = "point2d")
public class Point2D {
    public int x;
    public int y;
}

@UDT(name = "point3d")
public class Point3D extends Point2D {
    public int z;
}

public interface Shape2D {

    @Transient
    double getArea();

}

public interface Shape3D {

    @Transient
    double getVolume();

}

public abstract class Shape {

    private UUID id;

    @PartitionKey
    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }
    
}

@Table(name = "rectangles")
public class Rectangle extends Shape implements Shape2D {

    private Point2D bottomLeft;
    private Point2D topRight;

    @Column(name = "bottom_left")
    @Frozen
    public Point2D getBottomLeft() {
        return bottomLeft;
    }

    public void setBottomLeft(Point2D bottomLeft) {
        this.bottomLeft = bottomLeft;
    }

    @Column(name = "top_right")
    @Frozen
    public Point2D getTopRight() {
        return topRight;
    }

    public void setTopRight(Point2D topRight) {
        this.topRight = topRight;
    }

    @Transient
    public double getWidth() {
        return Math.abs(topRight.x - bottomLeft.x);
    }

    @Transient
    public double getHeight() {
        return Math.abs(topRight.y - bottomLeft.y);
    }

    @Override
    public double getArea() {
        return getWidth() * getHeight();
    }
    
}

@Table(name = "spheres")
public class Sphere extends Shape implements Shape3D {

    private Point3D center;
    private double radius;

    @Frozen
    public Point3D getCenter() {
        return center;
    }

    public void setCenter(Point3D center) {
        this.center = center;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double getVolume() {
        return 4d / 3d * Math.PI * Math.pow(getRadius(), 3);
    }

}
```

One powerful advantage of annotating getter methods is that
annotations are inherited from overridden methods in superclasses and superinterfaces;
in other words, if a getter method is overridden in a subclass, annotations in both
method declarations will get merged together. If duplicated annotations are found during this merge
process, the overriding method's annotations will take precedence over the overridden's.