CodamAIDocs
Topicdone

Generated code and custom code

Why generated code is never changed by hand, and where your custom code belongs: hooks, custom filters, custom controllers and services, configuration.

Variants
generated, do not touchHookcustom filterattribute filtercustom controller or serviceconfiguration

What this is about

A CDMS project has two kinds of code. The generated code is created by the build from the model in the hub, see Code generation in the build. The custom code is written by you: business logic that cannot be modeled.

The two live in different places and have different owners. If you keep them apart, you can regenerate at any time without losing anything.

What lives where

flowchart TB
    subgraph T["target/generated-sources/ · generated, recreated on every build"]
        A["OrderApi"] --> S["OrderSystem"] --> D["OrderDatabase"]
        S --> AL["OrderAuthorizationLayer"]
        M["OrderEntity, OrderDto, Payloads, Mapper, MetaService"]
    end
    subgraph SRC["src/main/java/ · yours, in the repository"]
        H["OrderHook<br/>(Hook)"]
        F["OrderFilter<br/>(Filter)"]
        C["custom controller<br/>or service"]
        ST["Start.java<br/>(created once)"]
    end
    subgraph R["src/main/resources/ · yours"]
        Y["application.yaml"]
    end
    H -. "is called by" .-> S
    F -. "is asked by" .-> S
    C -- "calls" --> S
LocationOwnerin the repository?what happens during the build
target/generated-sources/annotations/Generatornois recreated
src/main/java/youyesis compiled, never overwritten
src/main/resources/youyesis packaged, never overwritten
pom.xml between the cdms-managed markersHubyesis kept up to date, see Project scaffold

Where does my logic go?

Which extension point fits?
What do you want to do?Extension point
add a field, a rule, an endpoint, a rolechange the model in the hub and build again, no code
check, calculate or trigger something before or after savingHook on the model
hide rows depending on a user attributeaccess filter in the hub, a custom filter class if needed
restrict every search on a model with your own logiccustom filter
offer a business endpoint that CDMS does not knowcustom controller that calls the system layer
adjust the behavior of CDMSconfiguration in application.yaml or the environment
change a generated classnot possible, the change is gone after the next build

Hooks

A hook is a class that CDMS calls on every operation on a model. You write it for the model’s entity:

@Service
@Order(100)
public class OrderHook implements HookServiceInterface<OrderEntity> {

  @Override
  public void beforeDatabaseChange(OrderEntity item, CmsMethods method)
      throws AbstractCodamaiException {
    if (method == CmsMethods.CREATE && item.getOrderNr() == null) {
      item.setOrderNr(nextNumber());
    }
  }

  @Override
  public void afterDatabaseChange(OrderEntity item, CmsMethods method)
      throws AbstractCodamaiException {
    // e.g. publish an event
  }

  @Override
  public void fieldBeforeDatabaseChange(OrderEntity item, String field, CmsMethods method) { }

  @Override
  public void fieldOnDatabaseRead(OrderEntity item, String field, CmsMethods method) { }
}
  1. 1
    Developer
    writes a class that implements HookServiceInterface<OrderEntity>
  2. 2
    Developer
    makes it a Spring bean with @Service and gives it an @Order
    @Order sets the order when there are several hooks on the same model. Smaller number first. Put it directly on the class.
  3. 3
    CDMS
    finds all hook beans for OrderEntity and sorts them by @Order
  4. 4
    Hook
    is called on every operation, with the operation as CmsMethods
    CREATE, READ, UPDATE, PATCH, DELETE, ROLLBACK

The work is done by beforeDatabaseChange (before writing, inside the transaction) and afterDatabaseChange (after writing, and when reading after loading). If a hook throws an AbstractCodamaiException, the whole operation stops and the transaction is rolled back. Exactly when which hook runs is described in Hooks: kinds and timing and Order of hooks.

Custom filters

A filter restricts every search on a model before it reaches the database. It works with the model’s DTO. The most common case is an attribute filter: each user sees only the rows whose field matches an attribute in their token. For this there is the ready-made base class AbstractAttributeFilter:

@Service
public class OrderFilter extends AbstractAttributeFilter<OrderDto> {
  @Getter
  private final String dataAttribute = "companyId";   // field on the model
  @Getter
  private final String profileAttribute = "company";  // attribute in the user's token
}
What the attribute filter makes of the token
Value of the attribute in the tokenCondition in the search
one value, e.g. c-17companyId = 'c-17'
several valuescompanyId IN (…)
*no filter, all rows
missing or emptyrequest is rejected

If you need different logic, you implement CdmsFilterInterface<OrderDto> directly and return your own search filter in get(). If you create an access filter in the hub, the generator creates the filter class itself. More in Attribute filter and Custom data filters.

Custom controllers and services

For business processes that go beyond create, read, update and delete, you write a normal Spring @RestController. It calls the generated system layers. This way its calls also go through permission checks, validation and hooks.

The generated OrderApi, on the other hand, you do not extend or replace. The generated beans have fixed names. A second bean with the same name stops the application from starting.

Configuration

What you can adjust in CDMS is set in application.yaml or comes from the environment:

Propertywhat for
codamai.cdms.api.createReadModehow strict reading back after a create is (STRICT, LENIENT)
codamai.cdms.cias.reader-rolesroles that may read the role declaration
codamai.cdms.persistence.file.basePathstorage location for files
codamai.debugstack trace in error responses (false in production)
CODAMAI_PERSISTENCE_TENANT_MODESINGLE or MULTI
CODAMAI_PERSISTENCE_DATABASE_*driver, URL, user, password of the database

Pitfalls

Sources in the code and the knowledge base
  • CDMS/cdms-generator – generator/CdmsProcessor, AbstractProcessor (createSourceFileOrSkip), StartClassProcessor
  • commons – global/commons/interfaces/HookServiceInterface, CmsMethods
  • CDMS/cdms-system-layer – HookManagementSystem, AbstractLayer (getCdmsFilter)
  • CDMS/cdms-commons – interfaces/CdmsFilterInterface
  • CDMS/cdms-authorization – security/AbstractAttributeFilter
  • CDMS/cdms-integrationtest – order/OrderFilter, vault/VaultFilter
  • hub-backend – services/FolderHook, ModelDesignApi
  • documentation/60-erweiterung/01-hooks.md, 03-eigene-filter.md
Search