You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -191,6 +191,8 @@ The Builder constructor simply takes an IAerospikeClient which it uses for acces
191
191
192
192
`withConfigurationFile`: Whilst mapping information from POJOs via annotations is efficient and has the mapping code inline with the POJO code, there are times when this is not available. For example, if an external library with POJOs is being used and it is desired to map those POJOs to the database, there is no easy way of annotating the source code. Another case this applies is if different mapping parameters are needed between different environments. For example, embedded objects might be stored in a map in development for ease of debugging, but stored in a list in production for compaction of stored data. In these cases an external configuration YAML file can be used to specify how to map the data to the database. See [External Configuration File](#external-configuration-file) for more details. There is an overload of this method which takes an additional boolean parameter -- if this is `true` and the configuration file is not valid, errors will be logged to `stderr` and the process continue. It is normally not recommended to set this parameter to true.
193
193
194
+
If multiple configuration files are used and the same class is defined in multiple configuration files, the definitions in the first configuration file for a class will be used.
195
+
194
196
`withConfiguration`: Similar to the `withConfigurationFile` above, this allows configuration to be externally specified. In this case, the configuration is passed as a YAML string.
195
197
196
198
`withReadPolicy`, `withWritePolicy`, `withBatchPolicy`, `withScanPolicy`, `withQueryPolicy`: This allows setting of the appropriate policy type. The following discussion uses read policies, but applies equally to all the other policies.
@@ -1034,7 +1036,77 @@ Multiple ordinals can be specified for a single class, but these must be sequent
1034
1036
1035
1037
#### The importance of GenericTypes
1036
1038
1037
-
When using the object mapper, it is important to
1039
+
When using the object mapper, it is important to use generics to describe the types as fully as possible. For example instead of `List accounts;` this should be `List<Account> accounts;`.Not only is this best practices forJava, but it gives the AeroMapper hints about what is mapped so it can optimize the type and minimize the amount of reflection needed at runtime and hence minimize the performance cost.
1040
+
1041
+
For example, assume there is a mapped type "B", and another "A" which has a list of B's:
1042
+
1043
+
```java
1044
+
@AerospikeRecord(namespace = "test", set = "A")
1045
+
public static class A {
1046
+
@AerospikeKey
1047
+
public int id;
1048
+
public List<B> listB;
1049
+
1050
+
public A() {
1051
+
listB = new ArrayList<>();
1052
+
}
1053
+
}
1054
+
1055
+
@AerospikeRecord(namespace = "test", set = "B")
1056
+
public static class B {
1057
+
@AerospikeKey
1058
+
public int id;
1059
+
public String name;
1060
+
}
1061
+
```
1062
+
1063
+
In this case, the AeroMapper knows that the `listB` object contains either B's or sub-classes of B's. If they're B's, it knows the type (it assumes they're of the declared type by default) and hence needs no extra information to describe it. If an element is a subclassof B it would include the type name in the object reference. In this case we store a B:
1064
+
1065
+
```java
1066
+
B b = new B();
1067
+
b.id = 2;
1068
+
b.name = "test";
1069
+
mapper.save(b);
1070
+
1071
+
A a = new A();
1072
+
a.id = 1;
1073
+
a.listB.add(b);
1074
+
mapper.save(a);
1075
+
```
1076
+
1077
+
1078
+
But in this case, the object is of the declared type (B) so this needs no type information. Hence, the object stored in the database is:
1079
+
1080
+
```
1081
+
id: 1
1082
+
listB: LIST('[2]')
1083
+
```
1084
+
1085
+
However, if the classA was declared as:
1086
+
1087
+
```java
1088
+
publicstaticclassA {
1089
+
@AerospikeKey
1090
+
publicint id;
1091
+
publicList listB;
1092
+
1093
+
1094
+
publicA() {
1095
+
listB =newArrayList<>();
1096
+
}
1097
+
}
1098
+
```
1099
+
1100
+
(Note the only difference is that the `List<B> listB` has now become `List listB`).
1101
+
1102
+
Inthiscase, the AeroMapper no longer has any type information so it needs to store full type information against each element in the list:
1103
+
1104
+
```
1105
+
id:1
1106
+
listB:LIST('[[2, "@T:B"]]')
1107
+
```
1108
+
1109
+
Note that the element is annotated with `@T:` and the short name of the type. (Theshort name of the type must be unique within the system, and can be changed using the `shortName` attribute of the `AerospikeRecord` annotation.
1038
1110
1039
1111
----
1040
1112
@@ -1575,37 +1647,83 @@ classes:
1575
1647
name: data
1576
1648
```
1577
1649
1578
-
The structure of the file is:
1650
+
### File Structure
1651
+
The structure of the file is:
1579
1652
1580
-
Top level is an array of classes. Each classhas:
1581
-
- **class**: the name of the class. This must match the full classname to which you want to apply the configuration
1582
-
- **namespace**: The namespace to map this classto. Can be unspecified if the classis only ever used for embedding in another object
1583
-
- **set**: The set to map this classto. Can be unspecified if the classis only ever used for embedding in another object
1584
-
- **durableDelete** (boolean): If set to `true`, any deletes on this classwill use [durable deletes](https://www.aerospike.com/docs/guide/durable_deletes.html). If not set, it will use the flag from the policy for this class
1653
+
Top level is an array of classes. Each classhas:
1654
+
- **class**: the name of the class. This must match the full classname to which you want to apply the configuration
1655
+
- **namespace**: The namespace to map this classto. Can be unspecified if the classis only ever used for embedding in another object
1656
+
- **set**: The set to map this classto. Can be unspecified if the classis only ever used for embedding in another object
1657
+
- **durableDelete** (boolean): If set to `true`, any deletes on this classwill use [durable deletes](https://www.aerospike.com/docs/guide/durable_deletes.html). If not set, it will use the flag from the policy for this class
1585
1658
- **mapAll** (boolean, default `true`): If true, all fields of this classwill automatically be mapped to the database. Fields can be excluded using `exclude` on the bin config. If this is set to false, only the fields specified with an explicit bin configuration will be stored.
1586
1659
- **sendKey** (boolean): If true, the key of the record will be stored in Aerospike. See [send key](https://www.aerospike.com/docs/guide/policies.html#send-key) for more details. If this is false, the key will not be stored in Aerospike. If not set, the `sendKey` field from the policy will be used.
1587
1660
- **ttl**: the time to live for the record, mapped to the expiration time on the policy. If not set, the expiration from the policy will be used.
1588
1661
- **shortName**: When this classname must be stored in the database, this is the name to store instead of the full classnames. This is used particularly for sub-classes. For example, if an Account classhas a Checking classand Savings classas subclasses, an object might store a reference to an Account (compiled type of Account), but this really is a Checking account (runtime type of Checking). If the reference to the account is persisted, a list storing the key and the type will be saved, and this name will be used as the type.
1589
-
- **key**: a key structure, specified below
1590
-
- **bins**: a list of bin structure, specified below
1662
+
- **key**: a [key structure](key-structure), specified below
1663
+
- **bins**: a list of [bin structure](bin-structure), specified below
1664
+
- **version**: The version of the record. Must be an integer with a positive value. If not specified, will default to 1. See [Versioning Links](versioning-links) for more details.
1591
1665
1666
+
#### Key Structure
1592
1667
The key structure contains:
1593
1668
- **field**: the field for the key. Can be unspecified if methods are being used for the key
1594
1669
- **getter**: the name of the method to be used as the getter for the key.
1595
1670
- **setter**: the name of the method to be used as the setter for the key. This is optional -- if lazy loading of referenced objects is used, a setter must be specified for the child classif a getter is
1596
1671
Note that either a field should be specified, or a getter (potentially with a setter). Using both a field and a getter will throw an error. Also note that the method is specified by names only, not parameters so it is a good idea to us a unique method.
1597
1672
1598
-
The bin structure contains:
1599
-
- **embed**:
1600
-
- **exclude**:
1601
-
- **field**:
1602
-
- **getter**:
1603
-
- **name**:
1604
-
- **ordinal**:
1605
-
- **reference**:
1606
-
- **setter**:
1673
+
#### Bin Structure
1674
+
The bin structure contains:
1675
+
- **embed**: An [embed structure](embed-structure) used for specifying that the contents of this bin should be included in the parent record, rather than being a reference to a child record. There can only be one embed structure per field, and if an embed structure is present, a [reference structure](reference-structure) cannot be. If a field refers to another AerospikeRecord, either in a collection or in it's own right, and neither an embed or reference structure is specified, a reference will be assumed by default.
1676
+
- **exclude**: A boolean value as to whether this bin should be mapped to the database. Defaults to true.
1677
+
- **field**: The name of the field which to which this bin is mapped. If this is provided, the getter and setter cannot be provided.
1678
+
- **getter**: The getter method used to populate the bin. This must be used in conjunction with a setter method, and excludes the use of the field attribute.
1679
+
- **name**: The name of the bin to map to. If this is not provided and a field is, this will default to the field name. The name must be provided if this bin maps to a getter/setter combination.
1680
+
- **ordinal**: For items mapped as lists, this ordinal specifies the location of this bin in the list. If this is not provided, the position of the bins in the list will be determined by alphabetical ordering.
1681
+
- **reference**: A [reference structure](reference-structure) detailing that a child object referenced by this bin should be stored as the key of the child rather than embedding it in the parent object. The use of a reference precludes the use of the embed attribute, and if neither is specified then reference is assumed as the default.
1682
+
- **setter**: The setter method used to map data back to the Java POJO. This is used in conjunction with the getter method and precludes the use of the field attribute. Note that the return type of the getter must match the type of the first parameter of the setter, and the setter can have either 1 or 2 parameters, with the second (optional) parameter being either of type [com.aerospike.client.Key](https://www.aerospike.com/apidocs/java/com/aerospike/client/Key.html) or Object.
1607
1683
1608
-
1684
+
#### Key Structure
1685
+
The key structure is used to specify the key to a record. Keys are optional in some situations. For example, if Object A embeds an Object B, B does not need a key as it is not stored in Aerospike in its own right.
1686
+
1687
+
The key structure contains:
1688
+
- **field**: The name of the field which to which this key is mapped. If this is provided, the getter and setter cannot be provided.
1689
+
- **getter**: The getter method used to populate the key. This must be used in conjunction with a setter method, and excludes the use of the field attribute.
1690
+
- **setter**: The setter method used to map data back to the Java key. This is used in conjunction with the getter method and precludes the use of the field attribute. Note that the return type of the getter must match the type of the first parameter of the setter, and the setter can have either 1 or 2 parameters, with the second (optional) parameter being either of type [com.aerospike.client.Key](https://www.aerospike.com/apidocs/java/com/aerospike/client/Key.html) or Object.
1691
+
1692
+
#### Embed Structure
1693
+
The embed structure is used when a child object should be fully contained in the parent object without needing to be stored in the database as a separate record. For example, it might be that Customer object contains an Address, but the Address is not stored in a separate table in Aerospike, but rather put into the database as part of the customer record.
1694
+
1695
+
The Embed structure contains:
1696
+
- **type**: The type of the top level reference. If this is just a reference to another object, eg
1697
+
1698
+
```java
1699
+
publicclassCustomer {
1700
+
...
1701
+
@AerospikeEmbed
1702
+
Address address;
1703
+
```
1704
+
1705
+
then the type refers to how the child will be stored in the parent. There are 2 options:LIST or MAP. Maps are more readable in that each bin in the child object is named, but this name consumes space in the database and hence this is the less efficient storage structure.
1706
+
1707
+
If the top level reference is a container class (ListorMap), then this type refers to how the list or map is represented in the database. For example,
1708
+
1709
+
```java
1710
+
public class Customer {
1711
+
...
1712
+
List<Address> address;
1713
+
```
1714
+
1715
+
Ifthis has a type of LIST, then the addresses in Aerospike will be stored in a list. Lists preserve the ordering in the original list. However, it can also be stored as a MAP, in which case the key of the sub-object (Address in thiscase) becomes the map key and the elements become the value in the map. Inthiscase the list ordering is NOT preserved upon retrieval -- the map elements are stored in a K_ORDERED map, so the elements will be returned sorted by their key.
1716
+
1717
+
-**elementType**:If the top level reference is a container (List or Map), this type specifies how the children objects are to be stored in Aerospike. For example, if `type =MAP` and `elementType =LIST` for the list of Customers in the above example, the bin in Aerospike will contain a K_ORDERED map, each of which will have an Address as the value, and the elements of the address will be stored in a list.
1718
+
1719
+
-**saveKey**:Boolean, defaults to false. This is useful when storing a list of elements as a LIST inside a MAP. Given the map key is the key of the record, it is often redundant to have the key stored separately in the list of values for the underlying object. However, if it is desired to have the key again in the list, set this value to true.
1720
+
1721
+
#### ReferenceStructure
1722
+
The reference structure is used when the object being referenced is not to be embedded in the owning object, but rather is to be stored in a separate table.
1723
+
-**lazy**:Boolean, defaults to false. When the parent object is loaded, references marked as lazy are NOT loaded. Instead a placeholder object is created with only the primary key information populated, so those objects can be loaded later.
1724
+
-**batchLoad**:Boolean, defaults to true. When the parent object is loaded, all non-lazy children will also be loaded. If there are several children, it is more efficient to load them from the database using a batch load. ifthis flag is set to false, children will not be loaded via a batch load. Note that if the parent object has 2 or less children to load, it will single thread the batch load as this is typically more performant than doing a very small batch. Otherwise the batchPolicy on the parent classwill dictate how many nodes are hit in the batch at once.
1725
+
- **type**: Either ID or DIGEST, defaults to ID. The ID option stores the primary key of the referred object in the referencer, the DIGEST stores the digest instead. Note that DIGEST is not compatible with `lazy=true` as there is nowhere to store the digest. (For example, if the primary key of the object is a long, the digest is 20 bytes, without dynamically creating proxies or subtypes at runtime there is nowhere to store these 20 bytes. Dynamically creating objects like this is not performant so is not allowed).
1726
+
1609
1727
## Virtual Lists
1610
1728
1611
1729
When mapping a Java object to Aerospike the most common operations to do are to save the whole object and load the whole object. The AeroMapper is set up primarily for these use cases. However, there are cases where it makes sense to manipulate objects directly in the database, particularly when it comes to manipulating lists and maps. This functionality is provided via virtual lists.
@@ -1614,13 +1732,9 @@ When mapping a Java object to Aerospike the most common operations to do are to
1614
1732
1615
1733
## To finish
1616
1734
- Document virtual lists
1617
-
- Validate some of the limits, eg bin name length, set name length, etc.
1618
-
- Make all maps (esp Embedded ones) K_ORDERED
1619
1735
- Add interfaceto adaptiveMap, including changing EmbedType
1620
1736
- Document all parameters to annotations and examples of types
1621
1737
- Document enums, dates, instants.
1622
-
- Document configuration file.
1623
-
- Document creation of builder -- multiple configuration files are allowed, if the same classis declared in both the first one encountered wins.
1624
1738
- Document methods with 2 parameters for keys and setters, the second one either a Key or a Value
1625
1739
- Document subclasses and the mapping to tables + references stored as lists
1626
1740
- Batch load of child items on Maps and References. Ensure testing of non-parameterized classes too.
0 commit comments