Bound mismatch error and java generic method

10,565

Solution 1

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>  {
...
}

Solution 2

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>.

Solution 3

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

Solution 4

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

protected static final <T extends Page<?>> T constructPage(...) 
{
    Page<?> p = null;
    //...
}
Share:
10,565
Selena
Author by

Selena

Updated on June 11, 2022

Comments

  • Selena
    Selena almost 2 years

    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);
        }
    }