简体   繁体   中英

Generic issues: T extends interface type. Cannot call method to return an object which extends the type?

I have this method declared in a parent class:

protected <ConfigT extends LoadableConfig> ConfigT getConfig(final String configId) {
    return (ConfigT)getConfigService().getConfig(configId, getDriver());
}

The configuration service method is defined as follows:

@SuppressWarnings("unchecked")
@Override
public <ConfigT extends LoadableConfig> ConfigT getConfig(String configId, WebDriver driver) {

    //noinspection unchecked
    Map<String,LoadableConfig> profile = profiles.get(getProfileName(driver));

    if(profile != null) {
        return (ConfigT) profile.get(configId);
    }

    return null;
}

The configuration type I want is here:

public interface AccessibleConfig extends LoadableConfig, PolleableConfig {
 ....
}

This line of code is throwing an incompatible type error:

 AccessibleConfig config = getConfig(ValidationPane.class.getCanonicalName());

How is this possible? The AccessibleConfig extends LoadableConfig . The method called declared that that return type is some type which extends LoadableConfig . I am running jdk1.8.0_102.jdk. This failure happens in IntelliJ as well as when compiling with Maven from the command line. I am able to do this with other configuration types which extends the LoadableConfig type.

EDIT:

Parent class:

public abstract class AbstractLoadable<T extends AbstractLoadable<T>> {

    private Map<String,LoadableConfig> profiles = new HashMap<>();

    protected <T extends LoadableConfig> T getConfig(final String configId) {
        return (T) profiles.get(configId);
    }
}

Concrete class:

public class ConcreteLoadable extends AbstractLoadable {

    public ConcreteLoadable(final String profileName) {

        AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName());
    }

}

And the interface types:

public interface LoadableConfig {
    Integer getLoadTimeoutInSeconds();
    void setLoadTimeoutInSeconds(final Integer loadTimeoutInSeconds);
}

public interface AccessibleConfig extends LoadableConfig {
    Boolean getHoverOverAccessorWithJavascript();
    void setHoverOverAccessorWithJavascript(final Boolean hoverOverAccessorWithJavascript);
    Boolean getClickAccessorWithJavascript();
    void setClickAccessorWithJavascript(final Boolean clickAccessorWithJavascript);
}

So, the exercise of producing this minimal example actually made it really easy to identify the source of the compiler error. I have posted an answer to this question below. I humbly accept that I did not in fact originally post a complete example.

I have identified the problem. The concrete class needs to pass itself to the parent because the parent is reflexively generic. The error message wasn't super helpful so I got tied up in thinking about the generic parameters of the parent class method and not of the generic parameters applied to the parent class itself.

The class declaration for ConcreteLoadable needs to changed to this to get rid of the compile error:

public class ConcreteLoadable extends AbstractLoadable<ConcreteLoadable> {

    public ConcreteLoadable(final String profileName) {

        AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM