Search

Model Reflection API

The Model Reflection API is a set of interfaces, which provide the ability to introspect a CDS model and retrieve details on the services, types, entities, and their elements that are defined by the model.

Content

The CDS Model

The interface CdsModel represents the complete CDS model of the CAP application and is the starting point for the introspection.

The CdsModel can be obtained from the EventContext

import com.sap.cds.services.EventContext;
import com.sap.cds.reflect.CdsModel;

@On(event = "READ", entity = "my.catalogservice.books")
public void readBooksVerify(EventContext context) {
    CdsModel model = context.getModel();
   [...]
}

or, in Spring, be injected.

On a lower level, the CdsModel can be obtained from the CdsDataStoreConnector.

Examples

The following examples are using this CDS model:

namespace my.bookshop {
  entity Books {
    title  : localized String(111);
    author : Association to Authors;
    ...
  }

  entity Authors {
    key ID : Integer;
    ...
  }

  entity Orders {
    OrderNo  : String @title:'Order Number';
    ...
  }
}

Get and inspect an element of an entity

In this example we introspect the details of the type of the element title of the entity Books:

CdsEntity books = model.getEntity("my.bookshop.Books");
CdsElement title = books.getElement("title");

boolean key = title.isKey();      // false
CdsType type = title.getType();   // CdsSimpleType

if (type.isSimple()) {   // true
  CdsSimpleType simple = type.as(CdsSimpleType.class);

  String typeName = simple.getQualifiedName();  // "cds.String"
  CdsBaseType baseType = simple.getType();      // CdsBaseType.STRING
  Class<?> javaType = simple.getJavaType();     // String.class
  Boolean localized = simple.get("localized");  // true
  Integer length = simple.get("length");        // 111
}

Get and inspect an association element of an entity

We can also analyze the details of an association:

CdsElement authorElement = book.getAssociation("author");
CdsAssociationType toAuthor = authorElement.getType();

CdsEntity author = toAuthor.getTarget(); // Entity: my.bookshop.Authors
boolean association = toAuthor.isAssociation();   // true
boolean composition = toAuthor.isComposition();   // false

Cardinality cardinality = toAuthor.getCardinality();
String sourceMax = cardinality.getSourceMax();    // "*"
String targetMin = cardinality.getTargetMin();    // "0"
String targetMax = cardinality.getTargetMax();    // "1"

Stream<CdsElement> keys = toAuthor.keys();  // Stream: [ ID ]
Optional<CqnExpression> onCondition = toAuthor.onCondition(); // empty

Find an annotation by name and get its value

Here, we programmatically check if the element OrderNo carries the annotation title and set the value of displayName depending on the presence of the annotation:

CdsEntity order = model.getEntity("my.bookshop.Orders");
CdsElement orderNo = order.getElement("OrderNo");

Optional<CdsAnnotation<String>> annotation = orderNo
        .findAnnotation("title");
String displayName = annotation.map(CdsAnnotation::getValue)
        .orElse(orderNo.getName());   // "Order Number"

Filter a stream of services for non-abstract services

Using a stream we determine all non-abstract services:

Stream<CdsService> services = model.services()
    .filter(s -> !s.isAbstract());
List<CdsService> serviceList = services.collect(Collectors.toList());

Filter a stream of entities by namespace

The static method com.sap.cds.reflect.CdsDefinition.byNamespace allows to create a predicate to filter a stream of definitions (e.g. entities, elements, …) for definitions contained in a given namespace:

import static com.sap.cds.reflect.CdsDefinition.byNamespace;
...

Stream<CdsEntity> entities = model.entities()
    .filter(byNamespace("my.bookshop"));

Get all elements with given annotation

The static method com.sap.cds.reflect.CdsAnnotatable.byAnnotation allows to create a predicate to filter a stream of annotatable model components (e.g. entities, elements, …) for components that carry a given annotation:

import static com.sap.cds.reflect.CdsAnnotatable.byAnnotation;
...

CdsEntity order = model.getEntity("my.bookshop.Orders");
Stream<CdsElement> elements = order.elements()
    .filter(byAnnotation("title"));

The CDS Model Reader

The CdsModelReader creates a CdsModel from an InputStream of CSN.

InputStream csnJson = ...
CdsModel model = CdsModelReader.readCsn(csnJson);

The CdsModelReader is not part of the public API. The initialization might change in future releases.