I'm working on a JavaFX application which is currently non-modular. If I would make my application modular then I would need to make many changes in other projects that are not fully under my command.
The problem is that I can't use the module java.smartcardio
without a module-info.java. Luckily, Eclipse allows me to add it manually (screenshot attached below).
But after each Maven Update
, I need to add it manually again. Is there another more convenient way to do it?
Code to reproduce the issue:
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();
}
}
SmartCardServices:
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;
}
}
Configuration:
<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>
It seems to be purely an IDE issue. I could not find a straightforward solution but two alternative ways of dealing with it.
First change manually the Eclipse .classpath file by replacing
<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>
with
<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>
Secondly, you add the module 'java.smartcardio' to the project by using the functionality 'Configure Build Path'.
If you do not want to repeat configuring build path again and again, you need to uncheck the box 'Update project configuration from pom.xml' ( which is by default selected ) whenever you do a 'Maven > Update Project'.
You can find additional information in the post: Eclipse maven compiler not supporting compiler-plugin compilerArgs