11
votes

I'm using Apache Olingo as an OData client for a Java SDK that I will provide for a RESTful OData API. In the SDK I want to be able to have strongly typed classes to represent the OData entities. I'm having trouble implementing this easily and thus feel like I'm missing a different strategy here.

The Olingo way seems to be to get an ODataClient object which provides the user with a bunch of useful methods for interacting with the API. The ODataClient is using a bunch of factory methods to build my request. For instance, this is the code I used to get the Customers from the Northwind sample OData service. client is an an instance of the necessary ODataClient class.

String serviceRoot = "http://services.odata.org/V4/Northwind/Northwind.svc";
URI customersUri = client.newURIBuilder(serviceRoot)
        .appendEntitySetSegment("Customers").build();
ODataRetrieveResponse<ODataEntitySetIterator<ODataEntitySet, ODataEntity>> response =
        client.getRetrieveRequestFactory().getEntitySetIteratorRequest(customersUri).execute();

if (response.getStatusCode() >= 400) {
    log("Error");
    return;
}

ODataEntitySetIterator<ODataEntitySet, ODataEntity> iterator = response.getBody();

while (iterator.hasNext()) {
    ODataEntity customer = iterator.next();
    log(customer.getId().toString());
}

I'd like to end up with a strongly typed entity from the iterator (i.e. Customer customer = iterator.next()). However, I'm not sure how to actually do that.

If I create a Customer class that extends ODataEntity and attempt to perform a cast such as Customer customer = (Customer) iterator.next() then I get a ClassCastException since the objects in the iterator are just ODataEntity objects and know nothing about the Customer subclass.

My next thought was to introduce generics but doing so will require what seems like a good amount of modification to the Olingo library which leads me to think that there is a better way to do this.

I'm using the development version of Apache Olingo 4 since the OData service must use OData 4.

What am I missing?

1

1 Answers

7
votes

It is not really advertised, but there is nowadays a POJO generator in Olingo, in the source tree at ext / pojogen-maven-plugin. Unfortunately for using the POJOs another layer with a different programming model is added, which holds entities cached in memory and syncs with OData service on a flush operation. I would be really interested in adapting it to a more conventional request/response model based on Olingos Request Factories.

However, you could try it out. In your pom include pojogen-maven-plugin and odata-client-proxy. The POJO generation can be triggered in the pom with

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>1.8</version>
        <executions>
            <execution>
                <phase>process-sources</phase>
                <goals>
                    <goal>add-source</goal>
                </goals>
                <configuration>
                    <sources>
                        <source>${project.build.directory}/generated-sources</source>
                    </sources>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.olingo</groupId>
        <artifactId>pojogen-maven-plugin</artifactId>
        <version>4.2.0-SNAPSHOT</version>
        <configuration>
            <outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
            <localEdm>${basedir}/src/main/resources/metadata.xml</localEdm>
            <basePackage>odata.test.pojo</basePackage>
        </configuration>
        <executions>
            <execution>
                <id>v4pojoGen</id>
                <phase>generate-sources</phase>
                <goals>
                    <goal>v4pojoGen</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

For the experiment I stored the EDM Metadataof the Olingo Car example service at src/main/resources/metadata.xml. Somehow the plugin wants to create an inbetween ojc-plugin folder and I just moved the generated Java code at the proper place manually.

At that point you have a Service.java and Java interfaces for each entity or complex type in the EDM model.

You can make use of it to read some entities like this

Service<EdmEnabledODataClient> service = odata.test.pojo.Service.getV4("http://localhost:9080/odata-server-sample/cars.svc");
Container container = service.getEntityContainer(Container.class);
for (Manufacturer m : container.getManufacturers()) {
    System.out.println(m.getName());
}