不同的Java库中的类重复会导致编译错误

时间:2019-02-09 08:38:15

标签: java selenium generics 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()
}

我的课程 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) {
        // TO SOMETHING
    }
}

现在,如果我编译该项目,则会出现以下错误:

The method touchWebElement(By, WebDriver) is ambiguous for the type Interactions    Interactions.java   line 8

我认为这是模棱两可的,因为接口 WebElement 存在两次。

如何解决该问题?

  • 使用appium-client <= 4.0.0可以,但是我需要更新的版本。
  • 当前,我刚刚从jar中删除了重复的程序包,并将此jar包含到我的项目中。我真的只是用7zip删除了它。这样可以清除编译错误,但是我可能很快会遇到其他问题,因为appium jar尚未完成,并且没有该包,appium项目甚至无法编译。
  • 硒家伙可能什么也不会改变(https://github.com/SeleniumHQ/selenium/pull/863)。
  • appium家伙可能不知道该如何解决,我也是:https://github.com/appium/java-client/issues/1021

我愿意接受所有解决问题的想法。预先谢谢你!

1 个答案:

答案 0 :(得分:3)

问题不是重复的类,而是泛型的使用方式。以下是一些MCVE来复制Appium WebDriver类中的情况:

package de.scrum_master.stackoverflow;

public interface WebElement {}
package de.scrum_master.stackoverflow;

public interface WebDriver {
  <T extends WebElement> T findElement();
}
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());
  }
}

说明:由于type erasure 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);
  }
}

这里绝对不需要重命名方法,重新打包任何类或执行其他类型的Maven / Gradle特技。