3

我从需要通用返回类型的方法中收到以下错误:

Description Resource    Path    Location    Type
Type mismatch: cannot convert from PageTypeOne to P SecuredPage.java

我可以通过将对象转换为泛型类型参数来消除错误,但我不明白为什么我需要在这个特定的方法中执行此操作,而不是在我在其他类的其他地方编写的其他类似方法中。

项目的基本结构是这样的:

用于不安全网页的基类 Page
用于所有安全网页的基类 SecuredPage

今天早些时候我有一个类似的问题,在 Stack Overflow 社区的帮助下得到了解决:Bound mismatch error and java generic method

我现在用类似的方法遇到了另一个问题。

带有构建页面的辅助方法的基本页面类是这样的:

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

SecuredPage 类如下:

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

    .....
}

这是我试图从 SecuredPage 中实现的方法——我希望能够有一个方法,该方法将返回两种类型的页面,这些页面是在我的 Web 应用程序中打开方法中的链接所产生的:

public final <P extends SecuredPage<P>> P loadContext(final String context) throws
NoSuchElementException {
    Menu m = pageHeader.getMenu();
    WebElement link = m.clickLink(context);
    String linkHref = link.getAttribute("href");

    if (linkHref.contains("somematchtext")) {
            return Page.constructPage(getDriver(), getTimeoutInSeconds(),   
                PageTypeOne.class); <==== This is where I get the error
    } else if (linkHref.contains("someothermatchtext")) {
            return Page.constructPage(getDriver(), getTimeoutInSeconds(), 
                PageTypeTwo.class); <==== This is wheere I get the error
    }
 }

PageTypeOne 和 PageTypeTwo 都扩展 SecuredPage:

public final class PageTypeOne extends SecuredPage<PageTypeOne> {
    .....
}


public final class PageTypeTwo extends SecuredPage<PageTypeTwo> {
    .....
}

我的 LoginPage 类中有一个类似的方法,如果有人尝试使用无效凭据登录,则返回 LoginPage;如果他们使用有效凭据登录,则返回 HomePage(扩展 SecuredPage)。我没有用那种方法得到这个错误。我的 Page 类中的constructPage 方法也没有出现错误,所以我真的不明白为什么我在 SecuredPage 中的 loadContext 方法出现此错误:

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

2 回答 2

3

P通常,编译器从方法签名(在您的情况下)推断出方法泛型类型(在您的情况loadContext下)。但是loadContext方法并没有P在参数上使用来帮助编译器推断P

相反,您正在强制编译器P从方法中推断类型。你想让它相信是PageTypeOne。不是这样工作的。

假设有人在方法调用中指定了泛型参数:

securedpageInstance.<SomeCompliantClassWithPBounds>loadContext(...)

SomeCompliantClassWithPBounds可能不同于PageTypeOne.

您的第二个示例有效,因为您有Class<T>方法login签名。编译器知道谁是T并且确定返回类型是相同的。

于 2013-04-08T21:31:05.310 回答
1

我同意 dcernahoschi 的回答。

要继续,您可以定义loadContext并使用从这里开始public final SecuredPage<? extends SecuredPage<?>> loadContext(...)的“未知”子类。 您还可以将代码更改为稍后,“欺骗”编译器以允许类似SecuredPage
loadContextreturn (P) Page.constructPage(...);PageTypeOne page = loadContext(...);

我强烈建议使用第一种方法,因为调用代码不应该知道loadContext(). 另一方面,如果调用代码期望加载某个页面,它应该传递页面的类(并且你去掉if/elsein loadContext),就像你的登录示例一样。

于 2013-04-08T22:19:36.163 回答