Я работаю над приложением 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>
@dan1st «Но кроме этого, добавление модуля-info.java, вероятно, будет работать лучше, если это возможно». Обратите внимание, что этот вопрос является продолжением предыдущего вопроса, где рекомендовалось сделать приложение немодульным.
О, я не знал, что вы имеете дело с разделенными пакетами, которые, как известно, вызывают некоторые проблемы. Кроме того, не все в ответе на самом деле является рекомендацией. Я часто включаю в ответы, которые пишу, несколько способов сделать что-то. Это не значит, что все они являются хорошими способами сделать это. (Лично я считаю, что следует избегать разделения пакетов, где это возможно, но да, есть случаи, когда это может оправдать отказ от модульности).
@dan1st Основная причина, по которой мы рекомендовали сделать приложение немодульным, заключалась в зависимости от автоматических модулей (например, Spring). Автоматические модули могут стать настоящей головной болью при развертывании приложения JavaFX. Если сделать приложение немодульным, это случайно решит проблему разделения пакета; хотя я согласен, в любом случае следует избегать разделенных пакетов.
@Billie Если я правильно понимаю, это чисто проблема IDE, да? Другими словами, вы можете прекрасно скомпилировать проект с помощью Maven, но Eclipse постоянно забывает, что вы добавили модуль ввода-вывода смарт-карты? Если да, попробуйте настроить плагин компилятора так, чтобы он добавил аргумент --add-modules java.smartcardio (как предложил dan1st), чтобы посмотреть, сможет ли Eclipse это уловить.
Только что нашел отчет об ошибке, что может означать, что добавление <compilerArgs>
может не сработать.
Аналогичный отчет об ошибке для Idea (исправлено в Idea для предстоящей версии IDE – еще не выпущено). Проблема в том, что, хотя модуль java.smartcardio
входит в стандартную JRE, он не добавляется в граф модуля по умолчанию JRE, поэтому вам нужно добавить его вручную как для компиляции, так и для выполнения --add-module java.smartcardio
как для javac
, так и для java
. В Idea вы можете добавить модуль в javac
в настройках IDE, но этот параметр перезаписывается импортом maven, поэтому вам придется повторно добавлять параметр после каждого импорта. Помимо этого работает.
@jewelsea, где находится импорт «jdk.internal.org.jline.terminal.Terminal.MouseTracking.Button»? Возможно, что-то пошло не так в процессе форматирования кода онлайн-инструментом...
@Billie Извините, упоминание jdk.internal.org.jline.terminal.Terminal.MouseTracking.Button'
было моей ошибкой. Я удалил комментарий. Моя IDE была настроена на добавление импорта. Когда я скопировал и вставил ваш код (в котором не было этой ссылки), IDE добавила неверную внутреннюю ссылку на кнопку, и я не осознавал, что это произошло. Я исправил свою локальную копию, чтобы использовать тот же импорт, что и в вашем вопросе. Все заработало нормально, как только я правильно настроил пути к модулям для JavaFX с помощью --module-path
и добавил модули javafx и java.smartcardio
в команды компиляции и Java: --add-modules
.
@Slaw да, похоже, это проблема исключительно IDE. Я добавил «<compilerArgs>» в свой файл pom и обновил проект через «Maven > Обновить проект». Eclipse по-прежнему жалуется на отсутствие библиотеки «javax.smartcardio…», но Maven успешно компилирует код с «<compilerArgs>» и без него.
Кажется, есть два альтернативных способа решения этой проблемы. Сначала вручную измените файл Eclipse .classpath. Во-вторых, снимите флажок «Обновить конфигурацию проекта из pom.xml» каждый раз, когда вы выполняете «Maven > Обновить проект...». Дополнительную информацию можно получить в посте по ссылке
Вы можете сами ответить на свой вопрос.
Кажется, это чисто проблема 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
Можете ли вы попробовать
add-modules java.smartcardio
к аргументам компилятора (используя<compilerArgs>
в<configuration>
maven-compiler-plugin
)? Но помимо этого, добавлениеmodule-info.java
, вероятно, будет работать лучше, если это возможно.