You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jackson序列化/反序列化BufferedImage时遇权限错误求助

问题:Jackson加载怪物JSON数据时触发BufferedImage序列化错误

我在开发游戏时尝试用JSON文件管理所有怪物数据,但使用Jackson加载数据时,出现了BufferedImage类的序列化/反序列化错误。我知道问题出在序列化操作上,但第一次用Java Jackson,不知道怎么修复。

MonsterManager代码

private static MonsterManager instance;
private ArrayList<shadowStandar> monsters;

private MonsterManager() {
    loadMonstersFromFile("res/Jsons/monsters.json"); // 根据你的文件位置调整路径
}

public static MonsterManager getInstance() {
    if (instance == null) {
        instance = new MonsterManager();
    }
    return instance;
}

private void loadMonstersFromFile(String filePath) {
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        monsters = objectMapper.readValue(new File(filePath), new TypeReference<ArrayList<shadowStandar>>() {});
    } catch (IOException e) {
        e.printStackTrace();
        // 适当处理异常
    }
}

public ArrayList<shadowStandar> getMonsters() {
    return monsters;
}
}

shadowStandar类代码

public class shadowStandar extends Entity {

    BufferedImage walkDown3,walkDown4,walkUp3,walkUp4,walkLeft3,walkLeft4,walkRight3,walkRight4;

    public int xpGiven;
    private String attackType;
    public BufferedImage combatImage;

    public shadowStandar(GamePanel gp) {
        super(gp);
    }

    @JsonCreator
    public shadowStandar(
            @JsonProperty("gp") GamePanel gp,
            @JsonProperty("name") String name,
            @JsonProperty("health") int health,
            @JsonProperty("str") int str,
            @JsonProperty("agi") int agi,
            @JsonProperty("mag") int mag,
            @JsonProperty("vit") int vit,
            @JsonProperty("xpGiven") int xpGiven,
            @JsonProperty("attackType") String attackType,
            @JsonProperty("combatImagePath") String combatImagePath,
            @JsonProperty("weaknesses") String[] weaknesses,
            @JsonProperty("resistances") String[] resistances,
            @JsonProperty("nulls") String[] nulls,
            @JsonProperty("repells") String[] repells
    ) {
        super(gp);
        type = 2;
        this.name = name;
        this.stats.hp = health;
        this.stats.maxHp = this.stats.hp;
        this.stats.str = str;
        this.stats.agi = agi;
        this.stats.mag = mag;
        this.stats.vit = vit;
        this.xpGiven = xpGiven;
        this.attackType = attackType;
        speed = 1;
        loadCombatImage(combatImagePath); // 加载特定的战斗图片
        getImage(); // 加载世界中的行走图片

        this.weaknesses = weaknesses;
        this.resistances = resistances;
        this.nulls = nulls;
        this.repells = repells;
    }

    public String getAttackType(){
        return attackType;
    }

    public int getPhysAttack(int playerEndurance,int attackerStat){
        return 5*(int)(Math.sqrt(((double) attackerStat/playerEndurance)*randomFactor()));
    }

    public void loadCombatImage(String combatImagePath){
        combatImage = setUp(combatImagePath);
    }
}

报错信息

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 类型`java.awt.image.BufferedImage`的定义无效:无法调用`setAccess()`访问`java.awt.image.BufferedImage`类的字段'colorModel',原因是`java.lang.reflect.InaccessibleObjectException`,问题:无法使私有字段java.awt.image.ColorModel java.awt.image.BufferedImage.colorModel可访问:模块java.desktop未向未命名模块@385c9627开放`java.awt.image`包
 at [Source: (File); line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:62)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadTypeDefinition(DeserializationContext.java:1893)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder._handleBadAccess(BeanDeserializerBuilder.java:620)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder._fixAccess(BeanDeserializerBuilder.java:537)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder.build(BeanDeserializerBuilder.java:384)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:295)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:151)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:415)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer(DeserializationContext.java:644)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:539)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:294)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:621)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:188)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:28)
    at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:867)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:659)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4956)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4826)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3657)
    at monster.MonsterManager.loadMonstersFromFile(MonsterManager.java:28)
    at monster.MonsterManager.<init>(MonsterManager.java:15)
    at monster.MonsterManager.getInstance(MonsterManager.java:20)
    at main.GamePanel.<init>(GamePanel.java:51)
    at main.Main.main(Main.java:14)
Caused by: java.lang.IllegalArgumentException: Failed to call `setAccess()` on Field 'colorModel' (of class `java.awt.image.BufferedImage`) due to `java.lang.reflect.InaccessibleObjectException`, problem: Unable to make field private java.awt.image.ColorModel java.awt.image.BufferedImage.colorModel accessible: module java.desktop does not "opens java.awt.image" to unnamed module @385c9627
    at com.fasterxml.jackson.databind.util.ClassUtil.checkAndFixAccess(ClassUtil.java:1008)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.fixAccess(FieldProperty.java:104)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder._fixAccess(BeanDeserializerBuilder.java:535)
    ... 26 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.awt.image.ColorModel java.awt.image.BufferedImage.colorModel accessible: module java.desktop does not "opens java.awt.image" to unnamed module @385c9627
    at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:387)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:363)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:311)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:181)
    at java.base/java.lang.reflect.Field.setAccessible(Field.java:175)
    at com.fasterxml.jackson.databind.util.ClassUtil.checkAndFixAccess(ClassUtil.java:995)
    ... 28 more
解决方案

问题根源

Jackson尝试自动序列化/反序列化shadowStandar类中的BufferedImage字段,但BufferedImage属于Java桌面模块(java.desktop),其内部私有字段受模块系统保护,Jackson无法通过反射访问这些字段;同时BufferedImage是二进制对象,不适合存储在纯文本的JSON文件中。

修复步骤

1. 让Jackson忽略BufferedImage字段

给所有BufferedImage字段添加@JsonIgnore注解,阻止Jackson尝试处理这些字段:

public class shadowStandar extends Entity {

    @JsonIgnore
    BufferedImage walkDown3,walkDown4,walkUp3,walkUp4,walkLeft3,walkLeft4,walkRight3,walkRight4;

    public int xpGiven;
    private String attackType;
    @JsonIgnore
    public BufferedImage combatImage;

    // 其余代码保持不变...
}

如果Entity父类中也有BufferedImage字段,同样需要给这些字段添加@JsonIgnore。

2. 确保JSON只存储图片路径

你的JSON文件中应该只存储图片的相对/绝对路径(比如combatImagePath),而不是图片对象本身。示例JSON结构:

[
    {
        "name": "Shadow Monster",
        "health": 100,
        "str": 20,
        "agi": 15,
        "mag": 10,
        "vit": 12,
        "xpGiven": 50,
        "attackType": "physical",
        "combatImagePath": "res/sprites/monsters/shadow_combat.png",
        "weaknesses": ["fire"],
        "resistances": ["dark"],
        "nulls": ["light"],
        "repells": []
    }
]

注意:GamePanel对象无法被Jackson序列化,需要在加载怪物后手动设置——比如在MonsterManager中遍历怪物,调用setGp方法传入实例。

3. 确认图片加载逻辑正常

你的@JsonCreator构造函数已经通过combatImagePath参数调用loadCombatImage加载图片,getImage方法也会加载行走动画图片,这部分逻辑保持不变即可。

4. 可选:优化ObjectMapper配置

如果存在未知字段导致的序列化错误,可以给ObjectMapper添加忽略未知字段的配置,并手动设置GamePanel:

private void loadMonstersFromFile(String filePath) {
    ObjectMapper objectMapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    try {
        monsters = objectMapper.readValue(new File(filePath), new TypeReference<ArrayList<shadowStandar>>() {});
        // 手动给每个怪物设置GamePanel
        GamePanel gp = new GamePanel(); // 或使用已有的GamePanel实例
        for(shadowStandar monster : monsters) {
            monster.setGp(gp); // 假设Entity类有对应的setter方法
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

总结

不要在JSON中存储二进制对象(比如BufferedImage),而是存储它们的路径或其他可序列化的元数据,在对象实例化后再手动加载二进制资源,这是游戏开发中管理资源的标准做法,既避免了序列化问题,也让JSON文件更简洁易维护。

内容的提问来源于stack exchange,提问作者Alejandrol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:32:02