存储Bank对象到Nitrite数据库时遇InvalidDefinitionException问题求助
问题:将Java对象存入Nitrite数据库时抛出Jackson序列化异常
尝试把Bank对象存入Nitrite文档型数据库的对象仓库时,抛出com.fasterxml.jackson.databind.exc.InvalidDefinitionException异常。已尝试在module-info.java中导出Bank类、给Bank类添加无参构造,但均未解决问题,需修复该错误。
完整错误信息
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type `com.app.bankapplet.bank.Bank`: Failed to construct BeanSerializer for [simple type, class com.app.bankapplet.bank.Bank]: (java.lang.IllegalArgumentException) Failed to call `setAccess()` on Field 'id' (of class `com.app.bankapplet.bank.Bank`) due to `java.lang.reflect.InaccessibleObjectException`, problem: Unable to make field private int com.app.bankapplet.bank.Bank.id accessible: module com.app.bankapplet does not "opens com.app.bankapplet.bank" to unnamed module @6293abcc at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:72) at com.fasterxml.jackson.databind.SerializerProvider.reportBadTypeDefinition(SerializerProvider.java:1280) at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanOrAddOnSerializer(BeanSerializerFactory.java:475) at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanOrAddOnSerializer(BeanSerializerFactory.java:295) at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:240) at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:174) at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1503) at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1451) at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:556) at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:834) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:307) at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4522) ... 18 more Exception running application com.app.bankapplet.Main
相关代码
Main.java
package com.app.bankapplet; import com.app.bankapplet.bank.Bank; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.stage.Stage; import javafx.util.Callback; import org.dizitart.no2.Nitrite; import org.dizitart.no2.objects.ObjectRepository; import java.io.File; import java.io.IOException; import java.util.Optional; public class Main extends Application { private static Nitrite db; private static Bank bank; @Override public void start(Stage stage) throws IOException { // Generates a bank bank = getBank(); ObjectRepository<Bank> bankObjectStore = db.getRepository(Bank.class); bankObjectStore.insert(bank); FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("main.fxml")); Scene scene = new Scene(fxmlLoader.load(), 800, 600); stage.setTitle("Bank Manager"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { db = Nitrite.builder() .filePath(new File("target/appdb.db")) .compressed() .openOrCreate(); launch(); } protected static Bank getBank() { Dialog<Bank> dialog = new Dialog<>(); dialog.setTitle("New Bank"); dialog.setHeaderText("Enter the name of the bank:"); Label label = new Label("Bank Name: "); TextField text = new TextField(); GridPane gridPane = new GridPane(); gridPane.add(label, 1, 1); gridPane.add(text, 2, 1); dialog.getDialogPane().setContent(gridPane); ButtonType buttonTypeOK = new ButtonType("OK", ButtonBar.ButtonData.OK_DONE); dialog.getDialogPane().getButtonTypes().add(buttonTypeOK); dialog.setResultConverter(new Callback<ButtonType, Bank>() { @Override public Bank call(ButtonType b) { if(b == buttonTypeOK) { return new Bank(text.getText()); } return null; } }); Optional<Bank> result = dialog.showAndWait(); if(result.isPresent()) { return result.get(); } return null; } }
Bank.java
package com.app.bankapplet.bank; import org.dizitart.no2.objects.Id; public class Bank { @Id private int id; private String name; public Bank() { } public Bank(String name) { this.id = 0; this.name = name; } public int getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private static String toTitleCase(String item) { if (item == null || item.isEmpty()) { return item; } StringBuilder convertedString = new StringBuilder(); boolean convertNext = true; for (char ch : item.toCharArray()) { if (Character.isSpaceChar(ch)) { convertNext = true; } else if (convertNext) { ch = Character.toTitleCase(ch); convertNext = false; } else { ch = Character.toLowerCase(ch); } convertedString.append(ch); } return convertedString.toString(); } }
module-info.java
module com.app.bankapplet { requires javafx.controls; requires javafx.fxml; requires nitrite; opens com.app.bankapplet to javafx.fxml; exports com.app.bankapplet.bank; exports com.app.bankapplet; }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>com.app</groupId> <artifactId>BankApplet</artifactId> <version>1.0-SNAPSHOT</version> <name>BankApplet</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>5.9.2</junit.version> </properties> <dependencies> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>20</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>20</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.1</version> </dependency> <dependency> <groupId>org.dizitart</groupId> <artifactId>nitrite</artifactId> <version>3.4.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>20</source> <target>20</target> </configuration> </plugin> <plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <!-- Default configuration for running with: mvn clean javafx:run --> <id>default-cli</id> <configuration> <mainClass>com.app.bankapplet/com.app.bankapplet.Main</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
解决方案
原因分析
错误核心是Java模块化权限限制:Nitrite底层依赖的Jackson属于未命名模块,需要反射访问Bank类的私有字段(如id),但当前模块仅导出com.app.bankapplet.bank包,未开放反射访问权限。exports仅允许其他模块访问公共类和成员,而反射需要opens权限。
修复步骤
修改module-info.java,添加opens语句开放com.app.bankapplet.bank包给未命名模块:
module com.app.bankapplet { requires javafx.controls; requires javafx.fxml; requires nitrite; opens com.app.bankapplet to javafx.fxml; // 新增该行,开放bank包的反射权限给未命名模块(Jackson所在模块) opens com.app.bankapplet.bank to unnamed module; exports com.app.bankapplet.bank; exports com.app.bankapplet; }
修改后,Jackson就能通过反射访问Bank类的私有字段,完成对象的序列化与存储。
内容的提问来源于stack exchange,提问作者TroyPilewski
相关产品推荐
相关产品推荐

