Повторяющиеся классы в разных библиотеках Java приводят к ошибкам компиляции - PullRequest
0 голосов
/ 09 февраля 2019

У меня проблемы с Java-клиентом appium, потому что кажется, что они сделали странные вещи со своим проектом.

В основном, они используют селен в своем проекте, который должен работать просто отлично, но они скопировали один пакет из селеначастично к их проекту ( 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) {
        // DO SOMETHING
    }
}

Теперь, если я скомпилирую этот проект, яполучить следующую ошибку:

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

Я думаю, что это неоднозначно, потому что интерфейс WebElement существует дважды.

Как я могу исправить эту проблему?

  • Использование appium-client <= 4.0.0 будет работать, но мне нужна более новая версия. </li>
  • В настоящее время я просто удалил дубликат пакета из jar и включил этот jar в свой проект.Я действительно просто удалил его с 7zip.Это устраняет эту ошибку компиляции, но я, вероятно, скоро столкнусь с другими проблемами, потому что jar-файл appium не завершен, и проект appium даже не скомпилируется без этого пакета.
  • Парни из селена, вероятно, ничего не изменят (https://github.com/SeleniumHQ/selenium/pull/863).
  • Парни из Appium, вероятно, не знают, как это исправить, поэтому я: https://github.com/appium/java-client/issues/1021

Решение:

С помощью принятого ответа я смог решить эти проблемы. Хотя мне нужно было найти немного другое решение. Проблема, с которой я столкнулся, заключалась в том, чтоклассы, которые вызывали мой 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");
    }
}

Это может быть не оптимальное решение, но оноработает и не нуждается в изменениях во всех других наших классах, и каждый может работать с этими методами взаимодействия, как до сих пор.

1 Ответ

0 голосов
/ 07 августа 2019

Проблема не в дублирующих классах, а в том, как используются дженерики.Вот немного 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());
  }
}

Объяснение: Из-за типа erasure doSomething универсальный тип возвращаемого значения <T extends WebElement> оценивается как Object, поэтому при попытке использовать этот результат для вызова myOverloadedMethod(..) компилятор не знает, какой метод выбрать.

Решение: Вам нужно помочь, приведя или явно объявив тип для переменной, содержащей параметр метода.

PS: Если вы измените определение интерфейса с interface WebDriver до interface WebDriver<T>, ошибка компиляции исчезнет.Но реализация Appium не делает этого, возможно потому, что они хотят оставаться максимально совместимыми (?) С исходным классом Selenium.Вы должны спросить их.


Обновление: Поскольку у ОП, похоже, возникли проблемы с пониманием моего ответа или с уверенностью, что я не пробовал его пример кода, который, конечно, я обычно использовалВоспроизведите и поймите его проблему:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...