Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
    }
}
like image 507
Selena Avatar asked Apr 08 '13 16:04

Selena


People also ask

What is bound mismatch in Java?

Bound mismatch: The type LivingThing is not a valid substitute for the bounded parameter <T extends Animal> of the type GenericClass<T>

How are bounds used with generics?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

Do generics prevent type cast errors?

Implementing generics into your code can greatly improve its overall quality by preventing unprecedented runtime errors involving data types and typecasting.

What is generic error in Java?

In cases where a transaction fails, the API Gateway can use a Generic Error to convey error information to the client based on the message type (for example, SOAP or JSON). By default, the API Gateway returns a very basic error to the client when a message filter fails.


2 Answers

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>  {
...
}
like image 192
rgettman Avatar answered Sep 20 '22 15:09

rgettman


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

like image 33
Christoph Walesch Avatar answered Sep 22 '22 15:09

Christoph Walesch