Global identifier generation conventions

DocumentKeyGenerator

You can setup a custom key generation strategy by supplying a custom function DocumentKeyGenerator. By default a session uses the HiLo algorithm:

final MultiDatabaseHiLoGenerator hiLoGenerator = new MultiDatabaseHiLoGenerator(32);
conventions.setDocumentKeyGenerator(new DocumentKeyGenerator() {
  @Override
  public String generate(String dbName, IDatabaseCommands dbCommands, Object entity) {
    return hiLoGenerator.generateDocumentKey(dbName, dbCommands, conventions, entity);
  }
});

However if you want the session to use an identity key generation strategy by default, you can overwrite this convention in the following manner:

conventions.setDocumentKeyGenerator(new DocumentKeyGenerator() {
  @Override
  public String generate(String dbName, IDatabaseCommands dbCommands, Object entity) {
    return store.getConventions().getTypeTagName(entity.getClass()) + "/";
  }
});

Function getTypeTagName will use either the convention specified in findTypeTagName (see below) or its default implementation.

FindTypeTagName

Entity objects that share a common tag name belong to the same collection on the server side. Tag names are also used to build document keys.

conventions.setFindTypeTagName(new TypeTagNameFinder() {
  @Override
  public String find(Class<?> clazz) {
    // function that provides the collection name based on the entity type
    return clazz.getSimpleName();
  }
});

TransformTypeTagNameToDocumentKeyPrefix

Actually, tag names determined by recently described convention functions aren't directly used as prefixes in document keys. There is a convention function called transformTypeTagNameToDocumentKeyPrefix which takes the collection name and produces the prefix:

conventions.setTransformTypeTagNameToDocumentKeyPrefix(new TypeTagNameToDocumentKeyPrefixTransformer() {
  @Override
  public String transform(String tag) {
    // transform the tag name to the prefix of a key, e.g. [prefix]/12
    throw new CodeOmitted();
  }
});

Its default behavior is that for a tag which contains one upper character it simply converts it to lower case string, e.g. Users would be transformed into users. For tag names containing more upper characters there will be no change, e.g. the tag name: LineItems would output the following prefix: LineItems.

FindJavaClassName and FindJavaClass

In metadata of all documents stored in a database you can find the following property which specifies the client-side type. For instance:

{
    "Raven-Java-Class": "com.example.orders.Shipper"
}

This property is used by RavenDB client to perform a conversion between java object and JSON document stored in a database. A function responsible for retrieving the java class of an entity is defined by findJavaClassName convention:

conventions.setFindJavaClassName(new JavaClassNameFinder() {
  @Override
  public String find(Class<?> clazz) {
    // use reflection to determine the type;
    return clazz.getSimpleName();
  }
});

To properly perform the revert conversion that is from a JSON result into a java object we need to retrieve the java class from Raven-Java-Class metadata:

conventions.setFindJavaClass(new JavaClassFinder() {
  @Override
  public String find(String id, RavenJObject doc, RavenJObject metadata) {
    return metadata.value(String.class, Constants.RAVEN_JAVA_CLASS);
  }
});

FindIdentityProperty

The client must know where in your entity an identifier is stored to be property able to transform it into JSON document. It uses findIdentityProperty convention for that. The default and very common convention is that a property named Id is the identifier, so it is the default one:

conventions.setFindIdentityProperty(new IdentityPropertyFinder() {
  @SuppressWarnings("boxing")
  @Override
  public Boolean find(Field field) {
    return "Id".equals(field.getName());
  }
});

You can provide a customization based on the field parameter to indicate which field keeps the identifier. The client will iterate over all object fields and take the first one according to the defined predicate.

FindIdentityPropertyNameFromEntityName

It can happen that sometimes the results returned by the server can haven't identifiers defined (for example if you run a projection query) however they have Raven-Entity-Name in metadata. Then to perform the conversion into java object a function that finds the identity property name for a given entity name is applied:

conventions.setFindIdentityPropertyNameFromEntityName(new IdentityPropertyNameFinder() {
  @Override
  public String find(String entityName) {
    return "Id";
  }
});

IdentityPartsSeparator

According to the default, convention document keys have the following format: [collectionName]/[identityValue]. The slash character (/) separates the two parts of an identifier. You can overwrite it by using identityPartsSeparator convention. Its default definition is:

conventions.setIdentityPartsSeparator("/");

IdentityTypeConvertors

RavenDB is designed to work with string identifiers. However it has the support for numeric and UUID ids. To be more exact it is able to work with int, long and UUID identifiers, because it has dedicated converters for them:

conventions.setIdentityTypeConvertors(Arrays.asList(
  new UUIDConverter(),
  new Int32Converter(),
  new Int64Converter()
  ));

If you need to have the support for different types of identifier properties, you can add a custom converter that implements ITypeConverter interface:

public static class UInt32Converter implements ITypeConverter {

  @Override
  public boolean canConvertFrom(Class<?> sourceType) {
    throw new CodeOmitted();
  }

  @Override
  public String convertFrom(String tag, Object value, boolean allowNull) {
    throw new CodeOmitted();
  }

  @Override
  public Object convertTo(String value) {
    throw new CodeOmitted();
  }
}
conventions.getIdentityTypeConvertors().add(new UInt32Converter());

FindIdValuePartForValueTypeConversion

You need to remember that even if the identity property of your entry isn't a string, a document in a database always has a string key. E.g. for the Orders entity that has a numeric ID and its value is 3, the server side key will be orders/3. If such document is fetched by RavenDB client, the key needs to be converted into a number. By default we look for the last part of the identifier after identityPartsSeparator:

conventions.setFindIdValuePartForValueTypeConversion(new IdValuePartFinder() {
  @Override
  public String find(Object entity, String id) {
    return id.split(conventions.getIdentityPartsSeparator())[1];
  }
});

FindFullDocumentKeyFromNonStringIdentifier

Sometimes the client needs to know the full id of the document that will be stored for an entity with non-sting identifier. We can use the following function:

conventions.setFindFullDocumentKeyFromNonStringIdentifier(new DocumentKeyFinder() {

  @Override
  public String find(Object id, Class<?> type, Boolean allowNull) {
    // by default returns [tagName]/[identityValue];
    throw new CodeOmitted();
  }
});

to find the full key based on the type of a document and the value type identifier.