简体   繁体   中英

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

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

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

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

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

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

如果您仍然面临相同的错误,请从 Window > Preferences > Java > Compiler > "Compiler Compilation level" -> 1.8 更改编译器级别的 JDK 1.8 或最新版本

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