Error serializing/deserializing BufferedImage using Jackson

218 views Asked by At

The Problem I am having is the following one. I am trying to handle all the enemys of my game in a Json File, when I try to load them, i get an error from Buffered Image class. I can More or less Understand it is because of Serialization and Deserialization, but I can't manage to figure out how to fix it because its my first time using Jackson in Java.

I tried the following code and i expected it to work like a normal Jackson constructor loader.

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

    private MonsterManager() {
        loadMonstersFromFile("res/Jsons/monsters.json"); // Ajusta la ruta según la ubicación de tu archivo 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();
            // Manejar excepciones apropiadamente
        }
    }

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

MonsterClass:

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); // Cargar la imagen de combate específica
        getImage(); // Cargar las imágenes del mundo

        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);
    }

I got the following error:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type `java.awt.image.BufferedImage`: 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 [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
1

There are 1 answers

0
Alejandrol On

Finally after tons of hours i found an alternative to fix it, if anyone is interested i leave here my aproach to the solution:

I created a new Class with only the Json arguments i needed to enter like the stats, the combatImagePath and the String Arrays.

I changed the monsterManager to be a monsterStatManager and finally in the constructor of the monsters i added a parameter of type monsterStat and assigned them normally.

    public shadowStandar(GamePanel gp,monsterData data) {
        super(gp);
        this.name = data.name;
        this.stats.hp = data.hp;
        this.stats.maxHp = this.stats.hp;
        this.stats.str = data.str;
        this.stats.agi = data.agi;
        this.stats.mag = data.mag;
        this.stats.vit = data.vit;
        this.xpGiven = data.xpGiven;
        this.attackType = data.attackType;
        this.combatImagePath = data.combatImagePath;
        this.resistances = data.resistances;
        this.weaknesses = data.weaknesses;
        this.nulls = data.nulls;
        this.repells = data.repells;
        this.type = 2;
        speed = 1;
        getImage();
    }

monsterData for Json class:

    // Constructor predeterminado sin argumentos
    public monsterData() {
    }

    // Constructor con argumentos anotado con @JsonCreator
    @JsonCreator
    public monsterData(
            @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
    ) {
        this.name = name;
        this.hp = health;
        this.maxHp = this.hp;
        this.str = str;
        this.agi = agi;
        this.mag = mag;
        this.vit = vit;
        this.xpGiven = xpGiven;
        this.attackType = attackType;
        this.combatImagePath = combatImagePath;

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