Search code examples
javagenericsolingo

Compile error with Java Generics and Apache Olingo 4


I’ve extended some of the base classes of Apache Olingo 4 (still in development) to allow for stronger typing. However, my use of generics is causing an error that I didn’t expect.

I have a type parameter E that extends FooODataEntity which in turn implements the ODataEntity interface. Since FooODataEntity is an ODataEntity (just more specific) I would expect this to compile with no issues. However, getEntities() has a compilation error as shown in the code below.

Also, I would expect to be able to specify List<E> as a return type for my override of getEntities() but then I get a compile error saying:

'getEntities()' in 'com.foo.restapi.client.olingo.FooEntitySet' clashes with 'getEntities()' in 'org.apache.olingo.commons.api.domain.v4.ODataEntitySet'; attempting to use incompatible return type

What am I missing here?

FooODataEntitySet:

package com.foo.restapi.client.olingo;

import com.foo.restapi.client.FooODataEntity;
import com.foo.restapi.client.exceptions.FooRuntimeException;

import org.apache.olingo.commons.api.domain.v4.ODataAnnotation;
import org.apache.olingo.commons.api.domain.v4.ODataEntity;
import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
import org.apache.olingo.commons.core.domain.AbstractODataEntitySet;

import java.lang.reflect.Constructor;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class FooEntitySet<E extends FooODataEntity> 
        extends AbstractODataEntitySet implements ODataEntitySet {

    private final List<E> entities = new ArrayList<E>();

    public FooEntitySet() {
        super();
    }

    @Override
    public List<ODataEntity> getEntities() {
        // compile error  
        // Incompatible types. Found: 'java.util.List<E>', 
        // required: 'java.util.List<org.apache.olingo.commons.api.domain.v4.ODataEntity>'

        return entities;
    }
}

FooODataEntity:

package com.foo.restapi.client;

public class FooODataEntity extends AbstractODataPayload 
        implements ODataEntity, ODataSingleton {

    // code not shown
}

Solution

  • There's a reason you can't do this. While a FooODataEntity is an ODataEntity, a List<FoodODataEntity> is not a List<ODataEntity>.

    Lets cover that in more detail:

    Say I have this class:

    public class BaconODataEntity implements ODataEntity {
        // Pretend I implement all the ODataEntity things
    }
    

    I can add an instance of BaconODataEntity into a List<BaconODataEntity> and a List<ODataEntity>... but not into a List<FooODataEntity>.

    So, simply letting you cast a List<FooODataEntity> to a List<ODataEntity> would destroy the very type safety that generics are meant to introduce as I could then add a BaconODataEntity to it

    So, how do you fix it? Well, if you absolutely need your List to be a List<E extends FooODataEntity>, create a new List and copy the elements into it and return that list.