And*_*ver 5 java generics selenium compiler-errors appium
我在使用appium java客户端时遇到了麻烦,因为似乎他们的项目做得很奇怪。
基本上,他们在项目中使用硒,这应该可以正常工作,但他们将硒中的一个软件包部分复制到了他们的项目中(org.openqa.selenium)中,并对内部的类进行了一些小的改动。基本上,他们向接口添加了泛型。现在,我们在不同库中的同一包中有重复的类,这当然会导致问题。
我创建了一个简单的Gradle项目来演示这一点。按照我的build.gradle:
plugins {
id 'java-library'
}
dependencies {
api 'io.appium:java-client:6.1.0'
}
repositories {
jcenter()
}
Run Code Online (Sandbox Code Playgroud)
还有我的课程Interactions.java:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class Interactions {
public static void touchWebElement(By by, WebDriver driver) {
touchWebElement(driver.findElement(by), driver);
}
public static void touchWebElement(WebElement element, WebDriver driver) {
// DO SOMETHING
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我编译该项目,则会出现以下错误:
The method touchWebElement(By, WebDriver) is ambiguous for the type Interactions Interactions.java line 8
Run Code Online (Sandbox Code Playgroud)
我认为这是模棱两可的,因为接口WebElement存在两次。
我该如何解决这个问题?
解:
在被接受的答案的帮助下,我得以解决了这些问题。尽管我需要提出一个稍微不同的解决方案。我面临的问题是,调用我的Interactions.java的类也需要进行这些转换,这会导致1000多次适应。为了防止这种情况,我更改了将Object作为参数的方法:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class Interactions {
public static void touchWebElement(Object object, WebDriver driver){
WebElement webElement = castObjectToWebElement(element, driver);
//DO SOMETHING
}
private static WebElement castObjectToWebElement(Object object, WebDriver driver) {
if (object instanceof WebElement) {
return (WebElement) object;
} else if (object instanceof By) {
return driver.findElement((By) object);
}
throw new IllegalArgumentException("Invalid type");
}
}
Run Code Online (Sandbox Code Playgroud)
它可能不是最佳解决方案,但是它可以工作,并且不需要在所有其他类中进行更改,并且到目前为止,每个人都可以使用这些Interaction方法。
问题不在于重复的类,而在于泛型的使用方式。这是一个复制 Appium 类中情况的MCVEWebDriver:
package de.scrum_master.stackoverflow;
public interface WebElement {}
Run Code Online (Sandbox Code Playgroud)
package de.scrum_master.stackoverflow;
public interface WebDriver {
<T extends WebElement> T findElement();
}
Run Code Online (Sandbox Code Playgroud)
package de.scrum_master.stackoverflow;
public class Application {
static WebDriver webDriver;
static void myOverloadedMethod(String text) {}
static void myOverloadedMethod(WebElement text) {}
public static void main(String[] args) {
// These 3 variants work
myOverloadedMethod("test");
myOverloadedMethod((WebElement) webDriver.findElement());
WebElement webElement = webDriver.findElement();
myOverloadedMethod(webElement);
// This one does not work
myOverloadedMethod(webDriver.findElement());
}
}
Run Code Online (Sandbox Code Playgroud)
说明:由于类型擦除 doSomething的通用返回类型<T extends WebElement>计算为Object,因此当尝试使用该结果来调用myOverloadedMethod(..)编译器时不知道选择哪个方法。
解决方案:您需要通过强制转换或显式声明包含方法参数的变量的类型来提供帮助。
PS:如果将接口定义从 修改interface WebDriver为interface WebDriver<T>,编译错误就会消失。但 Appium 的实现并没有这样做,也许是因为他们希望尽可能与原始 Selenium 类保持兼容(?)。你必须问他们。
更新:因为OP似乎无法理解我的答案,或者相信我没有尝试他的示例代码,当然我用它来重现和理解他的问题:
package de.scrum_master.appium;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class Interactions {
public static void touchWebElement(WebElement element, WebDriver driver) {}
public static void touchWebElement(By by, WebDriver driver) {
// Works
WebElement webElement = driver.findElement(by);
touchWebElement(webElement, driver);
// Works
touchWebElement((WebElement) driver.findElement(by), driver);
// Ambiguous due to type erasure -> does not work
touchWebElement(driver.findElement(by), driver);
}
}
Run Code Online (Sandbox Code Playgroud)
这里绝对不需要重命名方法、重新打包任何类或执行其他类型的 Maven/Gradle 特技。