Skip to main content

Generate a Typed OData Client With the OData Generator

The OData Generator allows for generating Java classes from the metadata of an OData service. These classes which are referred to as typed OData client provide type-safe access to the service.

Localisation

The generator is designed to generate source code in english. You may also generate a client based on other languages in the EDMX file. However, languages that use non-latin characters, specifically languages that read from right to left or that don't have capitalisation, may not be supported.

In general, there are three ways to use the generator:

  • Via the dedicated maven plugin
  • Via the command-line interface (CLI)
  • By instantiating and invoking it at runtime

The maven plugin is usually the recommended way as it integrates nicely with most project setups and makes configuration easy. However, the other two approaches are available and all are documented below.

For all three the required input is an EDMX file holding the service metadata.

OData v2 and OData v4

Please be aware that OData v2 and OData v4 service definitions are not interchangeable. There is a dedicated generator for each protocol version and it only accepts service definitions for that version.

Custom Data Types

The OData VDM generator does support all data types per the OData specification. If your OData service metadata uses a data type not listed in the standard, please alter your metadata to use a compatible data type from the specification instead.

For example, a non-standard Edm.Float type can be substituted by Edm.Single type from the OData specification.

Using the OData Generator

Regardless of how the generator is invoked the generated code requires some dependencies to be present. Therefore, it is required to ensure the following dependencies are present in your project:

<dependency>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-v4-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
Lombok and Dependency injection are mandatory!

Lombok and dependency injections are used by the generated typed OData client classes, that is why they are needed but only with the scope provided. Furthermore, some common IDEs (e.g. IntelliJ, Eclipse) require plugins to recognize these annotations. See the note on missing accessors

Using the OData Generator Maven Plugin

The maven plugin is most useful if you would like to use the generated code within a maven project. Use it by adding it to your application/pom.xml file under the <plugin> section:

<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-v4-generator-maven-plugin</artifactId>
<!-- Please use the latest version here-->
<version>4.XX.X</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/edmx</inputDirectory>
<outputDirectory>${project.build.directory}/vdm</outputDirectory>
<deleteOutputDirectory>true</deleteOutputDirectory>
<packageName>com.mycompany.vdm</packageName>
<defaultBasePath>odata/v4/</defaultBasePath>
<compileScope>COMPILE</compileScope>
<serviceMethodsPerEntitySet>true</serviceMethodsPerEntitySet>
<!-- (Optional) You can add a custom copyright header:
<copyrightHeader>Copyright (c) this year, my company</copyrightHeader>

Or use the SAP copyright header:
<sapCopyrightHeader>true</sapCopyrightHeader>
-->
</configuration>
</execution>
</executions>
</plugin>

Adapt the <inputDirectory> to point to the location of your service definitions. A full list of parameters is available here.

Now maven will run the generator within the process-sources phase which is executed before compile. The <compileScope> option instructs maven to add the generated code as sources for the compile phase.

caution

Usually, you will have to override the generated service path in the code. By default, the generator will use the namespace value of the <schema> tag as the service name. The URL path will be built as default-base-path + service-name. If your service definition does not contain this value or the value does not match what is needed in the URL then you need to override the service path in the code. Use the .withServicePath("/path/to/my/service") option on the service class.

Using the Plugin from the Command Line

The maven plugin can also be invoked without a project from the command line using -D parameter flags, for example:

mvn com.sap.cloud.sdk.datamodel:odata-v4-generator-maven-plugin:4.XX.X:generate -Dodatav4.generate.inputDirectory=foo -Dodatav4.generate.outputDirectory=bar

See the full list of parameters here.

Using the CLI

  1. Download the latest command-line interface (CLI) of the generator from Maven Central. Rename it to odata-generator-cli.jar and put it in a directory of your choice.
  1. Run java -jar odata-generator-cli.jar -i /path/to/input/folder -o /path/to/output/folder. You can also specify the parameter -p "my.package.name" to choose the package name and -b "/my/path" to choose the base path. A full list of parameters is available here.

  2. Put the generated Java source files from the output folder into your project that is using the SAP Cloud SDK so that they are picked up by Java. For example, move them to the application/src/main/java folder.

caution

Usually, you will have to override the generated service path in the code. By default, the generator will use the namespace value of the <schema> tag as the service name. The URL path will be built as default-base-path + service-name. If your service definition does not contain this value or the value does not match what is needed in the URL then you need to override the service path in the code. Use the .withServicePath("/path/to/my/service") option on the service class.

Generate Clients Programmatically

  1. Please include the odata-v4-generator artifact as a dependency in your project. Choose a module and location from which you intend to invoke the generator and add the following dependency to the appropriate pom.xml.
     <dependency>
    <groupId>com.sap.cloud.sdk.datamodel</groupId>
    <artifactId>odata-v4-generator</artifactId>
    </dependency>
  1. Copy the following code which will later invoke the generator:

    final Path inputDirectory = Paths.get("application/src/main/resources/");
    final Path outputDirectory = Paths.get("application/src/main/java/");
    final Path serviceNameMapping = inputDirectory.resolve("serviceNameMappings.properties");

    new DataModelGenerator()
    .withInputDirectory(inputDirectory.toFile())
    .withOutputDirectory(outputDirectory.toFile())
    .withServiceNameMapping(serviceNameMapping.toFile())
    .pojosOnly(false)
    .withNameSource(NameSource.NAME)
    .withPackageName("org.example")
    .withDefaultBasePath("/my/path/")
    .serviceMethodsPerEntitySet()
    .execute();
  2. Adapt the input & output directory as well as the package name according to your setup. A full list of parameters is available here. Place your EDMX file within the input folder and run the generator.

This should give you the generated classes in the desired folder. You can now proceed with using them to build requests.

In case you run into issues with the above process:

  • Double-check your service and file names
  • Check that the folders are set up correctly
  • The service name mappings meet your expectations
caution

Usually, you will have to override the generated service path in the code. By default, the generator will use the namespace value of the <schema> tag as the service name. The URL path will be built as default-base-path + service-name. If your service definition does not contain this value or the value does not match what is needed in the URL then you need to override the service path in the code. Use the .withServicePath("/path/to/my/service") option on the service class.

Available Parameters

The following parameters are available on the generator for both OData protocol versions:

ParameterDefaultDescription
<compileScope>NONEAdds the generated sources to the compilation or test phase
<copyrightHeader>nullCopyright header to be added at the top of generated files
<deleteOutputDirectory>FalseTarget directory is deleted before code generation
<defaultBasePath>-Base path of the exposed API
<includeEntitySets>-Only generate classes for specific entity sets
<includeFunctionImports>-Only generate classes for specific function imports
<inputDirectory>inputLocation of the metadata files
<namingStrategy>-Fully-qualified Java class to be used as the naming strategy
<nameSource>LABELSource for entity and property names (either LABEL or NAME)
<outputDirectory>outputOutput directory for generated sources
<overwriteFiles>FalseOverwrite existing files
<packageName>-Package name for the generated sources
<sapCopyrightHeader>FalseAdd the SAP copyright header (overrides copyrightHeader)
<serviceNameMappingFile>-Determine service names from a given mapping file
<serviceMethodsPerEntitySet>FalseGenerate service methods per each entity set for one entity type
<keepExistingSignatures>[^1]FalseTry to avoid API breaking changes by sticking to existing generated method[^2] signatures

[^1] Feature is in experimental state.

[^2] The keep existing signatures switch only works if the output directory already contains a generated client library.

More information is also available in the Javadoc of the generator implementation (OData v2, OData v4).

Available Naming Strategies

The SAP Cloud SDK offers two different naming strategies that can be used out-of-the-box:

  • com.sap.cloud.sdk.datamodel.odata.utility.S4HanaNamingStrategy (default)
  • com.sap.cloud.sdk.datamodel.odata.utility.SimpleNamingStrategy

While both strategies, of course, generate syntactically valid Java names, the S4HanaNamingStrategy tries to make the names as aligned with common Java coding convention as possible. This is achieved by stripping away common pre- and suffixes used in SAP service specifications, such as the prefix SAP_ or the suffix Type. Furthermore, some names are even extended by, for example, adding the prefix to to indicate a navigation property.

In contrast to that, the SimpleNamingStrategy performs only the bare minimum of modifications to convert the specified names into valid Java syntax.