Selena
Selena

Reputation: 2268

Bound mismatch error and java generic method

I am getting the following error:

Bound mismatch: The generic method constructPage(WebDriver, int, Class<T>) of type     
Page<T> is not applicable for the arguments (WebDriver, int, Class<HomePage>). The 
inferred type HomePage is not a valid substitute for the bounded parameter <T extends 
Page<T>>

I am trying to do a login and return a HomePage, if successful and a LoginPage if not using generics.

I have a base class, Page which is extended by SecuredPage for pages behind the login wall. I wrote a generic helper method that would construct pages of any type. This method is used by the login method on the LoginPage. LoginPage extends Page and HomePage extends SecuredPage. SecuredPage extends Page. The login method works if the LoginPage is returned, but I get the above error trying to return a HomePage. Since HomePage is a subclass of page because its parent class extends Page, I am confused as to why HomePage is not a valid substitute for the bounded parameter <T extends Page<T>>.

public abstract class Page<T extends Page<T>> extends SlowLoadableComponent<T> {

    protected static final <T extends Page<T>> T constructPage(WebDriver driver, 
    int timeoutInSeconds, java.lang.Class<T> pageClass) 
    {
        Page<T> p = null;

        try {
            Constructor<T> pageConstructor = pageClass.getConstructor(
            WebDriver.class, String.class, Integer.TYPE);
            p = pageConstructor.newInstance(driver, driver.getCurrentUrl(), 
                timeoutInSeconds);
            p.get();

        } catch(Exception e) {

        }

        return pageClass.cast(p);       
    }
}

This is the SecuredPage class:

public class SecuredPage extends Page<SecuredPage> {

    .....
}

And this is HomePage:

public final class HomePage extends SecuredPage {
    ......
}

This is LoginPage:

public final class LoginPage extends Page<LoginPage>  {


    public final HomePage loginWithGoodCredentials(final User user) {
        return login(user, HomePage.class);
    }

    public final LoginPage loginWithBadCredentials(final User user) {
        return login(user, LoginPage.class);
    }


    public final <T extends Page<T>> T login(final User user, final Class<T>     
            expectedPage) {
        enterUsername(user.getUsername());
        enterPassword(user.getPassword());
         loginButton.click();

        return Page.constructPage(getDriver(), getTimeoutInSeconds(), 
        expectedPage);
    }
}

Upvotes: 5

Views: 11251

Answers (5)

Chinnusamy
Chinnusamy

Reputation: 41

If you any one still face the same error change JDK 1.8 or latest version in compiler level from Window > Preferences > Java > Compiler > "Compiler Compilation level" -> 1.8

Upvotes: 0

newacct
newacct

Reputation: 122489

For the purposes of your constructPage method, you could just use

protected static final <T extends Page<?>> T constructPage(...) 
{
    Page<?> p = null;
    //...
}

Upvotes: 1

sanbhat
sanbhat

Reputation: 17622

If you still wish HomePage to extend SecuredPage with the presence of Bounded Generics, please pass the 'Generic Substitution' till HomePage.

Do not substitute Generic at SecuredPage, instead make SecuredPage as

public class  SecuredPage<T extends Page<T>> extends Page<T> {

}

and while creating HomePage, declare the value for the generic like this,

public class HomePage extends SecuredPage<HomePage> {

}

This should essentially solve the error

Upvotes: 1

rgettman
rgettman

Reputation: 178303

The problem is that HomePage is a Page<SecuredPage> and not a Page<HomePage>. The login method would return a Page<HomePage> from its generic signature.

You must make the generic parameter of HomePage related to itself, not SecuredPage. This will resolve the compiler error. Keep SecuredPage generic, but make sure its bound extends SecuredPage<T>. Then assign HomePage itself for the generic parameter T in HomePage.

class SecuredPage<T extends SecuredPage<T>> extends Page<T> {
...
}
class HomePage extends SecuredPage<HomePage>  {
...
}

Upvotes: 6

Christoph Walesch
Christoph Walesch

Reputation: 2427

Calling login(user, SecuredPage.class) works, but login(user, HomePage.class) does not. The reason is: type parameter T in SecuredPage is SecuredPage. HomePage is a subclass of SecuredPage, so the T type parameter of HomePage is SecuredPage as well.

Now, you call login with a Page<HomePage>. But such a class does not exist. HomePage is a subclass of Page<SecuredPage>.

Upvotes: 2

Related Questions