Download the example code

## What Is "Generic Persistent Class"

Each kind of persistent objects (such as "Artist" or "Painting") is described in Cayenne by a single ObjEntity. The most common and useful scenario is mapping an ObjEntity to a "specialized" Java class, one class per entity. But there is an alternative - use a single generic persistent object class to map any entity.

| Generic DataObject hints Accessing generic objects is done via DataObject API (see examples below). The simplest "generic" object class for all practical purposes is `CayenneDataObject`. "Concrete" DataObject classes are by definition "generic" as they implement `DataObject`.

| When to Use Generic Objects Generic objects are not type-safe and are not convenient for manual coding. Most applications should stick to concrete classes. Generic objects are useful in cases when all persistent properties are not fully known at compile time. It is also possible to use a hybrid approach when new persistent properties are added to the existing concrete class at runtime.

## Mapping in CayenneModeler

If you don't enter anything for Java Class of an ObjEntity, Cayenne assumes generic mapping and uses the following implicit rules to determine a class of a generic object. First it will check whether a DataMap "Custom Superclass" is set. If so, runtime uses this class to instantiate new objects. If not, `org.apache.cayenne.CayenneDataObject` is used.

CayenneModeler and Ant class generators skip ObjEntities that are mapped to CayenneDataObject explicitly or have no class mapping (i.e. implicitly mapped to a generic class).

## How to Use Generic DataObjects

#### Use String entity name in places where you would previously use Java class as a method argument to get a hold of a DataObject.

Create a new object:

    DataObject author = context.newObject("Person");

Build SelectQuery:

    Expression e = ExpressionFactory.likeIgnoreCaseExp("subject", "%first%");
    SelectQuery q = new SelectQuery("Message", e);

#### Use DataObject API to read/write the values instead or getters/setters.

Determine object entity name:

    DataObject object = ...;
    String entityName = object.getObjectId().getEntityName();

Read a simple property value (attribute or relationship):

    String subject = (String) object.readProperty("subject");

Read a "nested" property value spanning a chain of DataObjects:

    String name = (String) object.readNestedProperty("author.lastName");

Modify a property value:

    object.writeProperty("subject", "Post On Topic");