Как добавить модуль java.smartcardio в немодульное приложение JavaFX?

Я работаю над приложением JavaFX, которое в настоящее время не является модульным. Если бы я сделал свое приложение модульным, мне пришлось бы внести множество изменений в другие проекты, которые не полностью находятся под моим контролем.

Проблема в том, что я не могу использовать модуль java.smartcardio без модуля-info.java. К счастью, Eclipse позволяет мне добавить его вручную (скриншот прилагается ниже).

Но после каждого Maven Update мне нужно снова добавлять его вручную. Есть ли другой, более удобный способ сделать это?

Код для воспроизведения проблемы:

FxSmartCard:

package org.example.fxsmartcard;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import java.util.List;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import org.example.smartcardservice.SmartCardServices;

public class FxSmartCard extends Application {
  private SmartCardServices cardServices;
  public FxSmartCard() {
    super();
    this.cardServices = new SmartCardServices();
  }
  @Override
  public void start(Stage stage) {
    Label title = new Label("JavaFX meets SmartCard World!");
    title.setStyle("-fx-font-size: 32px;");
    final ComboBox < String > terminalComboBox = new ComboBox < String > ();
    List < CardTerminal > terminals = null;
    Button connect = new Button("Connect");
    try {
      terminals = cardServices.getTerminals();
      if (terminals != null && terminals.size() > 0) {
        for (CardTerminal terminal: terminals) {
          terminalComboBox.getItems().add(terminal.getName());
        }
        terminalComboBox.getSelectionModel().selectFirst();
        final List < CardTerminal > terminalList = terminals;
        connect.setOnAction(e -> {
          CardTerminal selectedTerminal = cardServices.getCardReader(terminalList,
            terminalComboBox.getSelectionModel().getSelectedItem());
          try {
            cardServices.connectToCard(selectedTerminal);
          } catch (CardException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
          }
        });
      } else {
        terminalComboBox.setValue("No Terminal present");
        connect.setDisable(true);
      }
    } catch (CardException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    GridPane gridpane = new GridPane();
    GridPane.setConstraints(terminalComboBox, 1, 0);
    GridPane.setConstraints(connect, 2, 0);
    gridpane.getChildren().addAll(terminalComboBox, connect);
    VBox layout = new VBox(10, title, gridpane);
    layout.setPadding(new Insets(12));
    Scene scene = new Scene(layout);
    stage.setScene(scene);
    stage.show();
  }
  public static void main(String[] args) {
    launch();
  }
}

СмартКардСервисы:

package org.example.smartcardservice;
import java.util.List;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
public class SmartCardServices {
  public List < CardTerminal > getTerminals() throws CardException {
    TerminalFactory factory = TerminalFactory.getDefault();
    return factory.terminals().list();
  }
  public void connectToCard(CardTerminal terninalSource) throws CardException {
    terninalSource.connect("*");
  }
  public CardTerminal getCardReader(List < CardTerminal > terminals, String name) {
    for (CardTerminal terminal: terminals) {
      if (terminal.getName().equals(name)) {
        return terminal;
      }
    }
    return null;
  }
}

Конфигурация:

<project xmlns = "http://maven.apache.org/POM/4.0.0"
    xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>JavaFXmeetsSmartCard</groupId>
    <artifactId>JavaFXmeetsSmartCard</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>21.0.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Можете ли вы попробовать add-modules java.smartcardio к аргументам компилятора (используя <compilerArgs> в <configuration>maven-compiler-plugin)? Но помимо этого, добавление module-info.java, вероятно, будет работать лучше, если это возможно.

dan1st 22.04.2024 08:27

@dan1st «Но кроме этого, добавление модуля-info.java, вероятно, будет работать лучше, если это возможно». Обратите внимание, что этот вопрос является продолжением предыдущего вопроса, где рекомендовалось сделать приложение немодульным.

Slaw 22.04.2024 18:37

О, я не знал, что вы имеете дело с разделенными пакетами, которые, как известно, вызывают некоторые проблемы. Кроме того, не все в ответе на самом деле является рекомендацией. Я часто включаю в ответы, которые пишу, несколько способов сделать что-то. Это не значит, что все они являются хорошими способами сделать это. (Лично я считаю, что следует избегать разделения пакетов, где это возможно, но да, есть случаи, когда это может оправдать отказ от модульности).

dan1st 22.04.2024 18:38

@dan1st Основная причина, по которой мы рекомендовали сделать приложение немодульным, заключалась в зависимости от автоматических модулей (например, Spring). Автоматические модули могут стать настоящей головной болью при развертывании приложения JavaFX. Если сделать приложение немодульным, это случайно решит проблему разделения пакета; хотя я согласен, в любом случае следует избегать разделенных пакетов.

Slaw 22.04.2024 18:54
smartcardio является частью среды выполнения Java. Если у вас есть немодульное приложение, оно уже должно быть частью стандартного пути к модулю среды выполнения. Для его использования вам не придется делать ничего дополнительного.
jewelsea 22.04.2024 19:11

@Billie Если я правильно понимаю, это чисто проблема IDE, да? Другими словами, вы можете прекрасно скомпилировать проект с помощью Maven, но Eclipse постоянно забывает, что вы добавили модуль ввода-вывода смарт-карты? Если да, попробуйте настроить плагин компилятора так, чтобы он добавил аргумент --add-modules java.smartcardio (как предложил dan1st), чтобы посмотреть, сможет ли Eclipse это уловить.

Slaw 22.04.2024 19:19

Только что нашел отчет об ошибке, что может означать, что добавление <compilerArgs> может не сработать.

Slaw 22.04.2024 19:36

Аналогичный отчет об ошибке для Idea (исправлено в Idea для предстоящей версии IDE – еще не выпущено). Проблема в том, что, хотя модуль java.smartcardio входит в стандартную JRE, он не добавляется в граф модуля по умолчанию JRE, поэтому вам нужно добавить его вручную как для компиляции, так и для выполнения --add-module java.smartcardio как для javac, так и для java. В Idea вы можете добавить модуль в javac в настройках IDE, но этот параметр перезаписывается импортом maven, поэтому вам придется повторно добавлять параметр после каждого импорта. Помимо этого работает.

jewelsea 22.04.2024 19:46

@jewelsea, где находится импорт «jdk.internal.org.jline.terminal.Terminal.MouseTracking.Butt‌​on»? Возможно, что-то пошло не так в процессе форматирования кода онлайн-инструментом...

Billie 22.04.2024 20:57

@Billie Извините, упоминание jdk.internal.org.jline.terminal.Terminal.MouseTracking.Butto‌​n' было моей ошибкой. Я удалил комментарий. Моя IDE была настроена на добавление импорта. Когда я скопировал и вставил ваш код (в котором не было этой ссылки), IDE добавила неверную внутреннюю ссылку на кнопку, и я не осознавал, что это произошло. Я исправил свою локальную копию, чтобы использовать тот же импорт, что и в вашем вопросе. Все заработало нормально, как только я правильно настроил пути к модулям для JavaFX с помощью --module-path и добавил модули javafx и java.smartcardio в команды компиляции и Java: --add-modules.

jewelsea 22.04.2024 21:49

@Slaw да, похоже, это проблема исключительно IDE. Я добавил «<compilerArgs>» в свой файл pom и обновил проект через «Maven > Обновить проект». Eclipse по-прежнему жалуется на отсутствие библиотеки «javax.smartcardio…», но Maven успешно компилирует код с «<compilerArgs>» и без него.

Billie 26.04.2024 13:01

Кажется, есть два альтернативных способа решения этой проблемы. Сначала вручную измените файл Eclipse .classpath. Во-вторых, снимите флажок «Обновить конфигурацию проекта из pom.xml» каждый раз, когда вы выполняете «Maven > Обновить проект...». Дополнительную информацию можно получить в посте по ссылке

Billie 26.04.2024 13:24

Вы можете сами ответить на свой вопрос.

jewelsea 27.04.2024 00:21
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
13
192
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Сначала измените вручную файл Eclipse .classpath, заменив

<classpathentry kind = "con" path = "org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
   <attributes>
      <attribute name = "maven.pomderived" value = "true" />
   </attributes>
</classpathentry>

с

<classpathentry kind = "con" path = "org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
   <attributes>
      <attribute name = "module" value = "true" />
      <attribute name = "limit-modules" value = "java.se,jdk.accessibility,jdk.dynalink,jdk.httpserver,jdk.incubator.vector,jdk.jartool,jdk.javadoc,jdk.jconsole,jdk.jshell,jdk.jsobject,jdk.management.jfr,jdk.net,jdk.nio.mapmode,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.unsupported.desktop,jdk.xml.dom,java.smartcardio" />
      <attribute name = "maven.pomderived" value = "true" />
   </attributes>
</classpathentry>

Во-вторых, вы добавляете в проект модуль java.smartcardio, используя функцию «Настроить путь сборки».

Если вы не хотите снова и снова повторять настройку пути сборки, вам необходимо снять флажок «Обновить конфигурацию проекта из pom.xml» (который выбран по умолчанию) каждый раз, когда вы выполняете «Maven > Обновить проект».

Дополнительную информацию вы можете найти в посте: Компилятор Eclipse maven не поддерживает компилятор-плагин-компиляторArgs

Другие вопросы по теме