具有不同对象类型的Jackson(去)序列化哈希图

问题描述 投票:0回答:2

我目前正在用 Java 编写游戏,并且在 Jackson 中保存实体数据时遇到问题。我需要使用超类的不同子类对哈希图进行(反)序列化。例如我有一个名为 mob 的类,每个实体(例如玩家)都是 Mob 的子类:

public HashMap<Byte, Mob> mobs = new Hashmap<>(); // Byte is ok here, as I don't have many mobs yet and it can also be changed to whatever I need to

public class Player extends Mob {} // The Player

我想如何序列化地图:

public void loadEntities(String path) {
        ObjectMapper om = new ObjectMapper();

        try {
            runThread.mobs = om.readValue(new File(path + "/entities.json"), HashMap.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

但是我需要做什么,才能让 hashmap 正确反序列化 JSON 文件中的生物玩家,然后将其作为玩家序列化回哈希映射中,而不是普通的生物对象?

我的 JSON 是什么样子的:

{
  "0" : {
    "posX" : 256,
    "posY" : 128,
    "rotation" : "links"
  },

  "2" : {
    "posX" : 128,
    "posY" : 256,
    "rotation" : "rechts"
  }
}

0 和 2 是实体的 ID,但如果需要,我可以将哈希图更改为列表。

我的暴民的完整示例:


import de.pki.GUI.Welt.Tiles.Tiles;

import java.awt.image.BufferedImage;

public abstract class Mob {
    public float posX;
    public float posY;

    public float screenX;
    public float screenY;

    // Physik

    public float forceX;
    public float forceY;

    public float gravity = 9.81F;
    public float currentGravity = gravity * 2;

    public float rotation; // Für Projektile, welche sich in der Luft drehen müssen
    public String richtung; // Für normale Mobs, welche nur zwei Richtungen brauchen
    public boolean vectorAble; // TODO

    public float standardSpeed;
    public float sprintSpeed;
    public float currentSpeed;

    public byte maxSpruenge = 2;
    public byte spruengeGenutzt;
    public float sprungKraft;
    public float aktuelleSprungkraft = -5;
    public float lastJump = System.currentTimeMillis();

    // Hit box

    public short startBoxX;
    public short startBoxY;
    public short endBoxX;
    public short endBoxY;

    public float opacity;

    // Bilder

    public BufferedImage idleLinks;
    public BufferedImage idleRechts;

    public BufferedImage[] links;
    public BufferedImage[] rechts;
    public BufferedImage currentImg;

    public byte groesse = 1;

    public byte imageCount = 0;
    public double lastImageAnimation = System.currentTimeMillis();

    // Methoden
    // Physik

    public void updateForces(CollisionChecker collisionChecker, int tickSpeed) {
        if (forceX > 0) {
            collisionChecker.checkRunning((int) (posX + startBoxX + endBoxX), forceX / tickSpeed, 1, this);
        } else if (forceX < 0) {
            collisionChecker.checkRunning((int) (posX + startBoxX - 4), (forceX * - 1) / tickSpeed, -1, this);
        }

        if (forceY > 0) {
            collisionChecker.checkFalling((int) (posY + startBoxY + endBoxY), forceY / tickSpeed, 1, this);
        } else if (forceY < 0) {
            collisionChecker.checkFalling((int) (posY + startBoxY - 2), (forceY * - 1) / tickSpeed, -1, this);
        }
    }

    public void gravity(double tickSpeed) {
        forceY += (float) (currentGravity / tickSpeed);
    }

    public void jump() {
        if (lastJump + 500 < System.currentTimeMillis()) {
            if (spruengeGenutzt < maxSpruenge) {
                forceY = aktuelleSprungkraft;
                spruengeGenutzt++;

                lastJump = System.currentTimeMillis();
            }
        }
    }

    // Für Objekte, welche Vektoren besitzen

    public void changeVektor(Mob mob, Tiles tiles, double aufprallWinkel) {
        if (mob.vectorAble) {}

        // TODO: Noch hinzufügen
    }

    // Grafische Sachen

    public void updateImages() {
        switch (richtung) {
            case "rechts" -> {
                if (System.currentTimeMillis() - lastImageAnimation >= (double) 60 / rechts.length / 1000 + 150) {
                    if (imageCount + 1 >= rechts.length) {
                        imageCount = 0;
                    } else {
                        imageCount++;
                    }

                    currentImg = rechts[imageCount];
                    lastImageAnimation = System.currentTimeMillis();
                }
            }
            case "links" -> {
                if (System.currentTimeMillis() - lastImageAnimation >= (double) 60 / links.length / 1000 + 150) {
                    if (imageCount + 1 >= links.length) {
                        imageCount = 0;
                    } else {
                        imageCount++;
                    }

                    currentImg = links[imageCount];
                    lastImageAnimation = System.currentTimeMillis();
                }
            }
        }

        if (forceX == 0) {
            if (richtung.equals("rechts")) {
                currentImg = idleRechts;
            } else if (richtung.equals("links")) {
                currentImg = idleLinks;
            }
        }
    }
}

还有我的玩家:

package de.pki.Entities.Spieler;

import de.pki.Entities.Mob;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Spieler extends Mob {
    public Spieler() {
        loadVariables();
        loadImages();

        hitBoxRechts();
    }

    private void loadImages() {
        try {
            links = new BufferedImage[2];
            rechts = new BufferedImage[2];

            idleLinks = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/Idle/left_idle.png"));
            idleRechts = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/Idle/right_idle.png"));

            links[0] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/linksLauf1.png"));
            links[1] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/linksLauf2.png"));

            rechts[0] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/rechtsLauf1.png"));
            rechts[1] = ImageIO.read(new FileInputStream("src/Data/Images/Entities/Spieler/WalkingAnimation/rechtsLauf2.png"));

            currentImg = idleRechts;
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    private void loadVariables() {
        sprungKraft = (float) (-9.81 * 1);
        aktuelleSprungkraft = sprungKraft;
        maxSpruenge = 2;
        spruengeGenutzt = 0;

        standardSpeed = 3;
        sprintSpeed = 4.5F;
        currentSpeed = standardSpeed;

        richtung = "rechts";

        groesse = 2;

        hitBoxRechts();
    }

    public void hitBoxRechts() {
        startBoxX = (short) (6 * groesse);
        startBoxY = (short) (3 * groesse);
        endBoxX = (short) (19 * groesse);
        endBoxY = (short) (23 * groesse);
    }
}```

(I'm currently in class, so it took me some time to edit the code)
Thanks for the help
java jackson hashmap
2个回答
0
投票

参见 https://www.baeldung.com/java-deserialize-generic-type-with-jackson

你可以做

TypeReference typeRef = new TypeReference<Map<Byte, Mob>>() {};
runThread.mobs = om.readValue(new File(path + "/entities.json"), typeRef);

0
投票

要正确序列化多态实例,您需要使用注释

JsonTypeInfo
JsonSubTypes
。基本上,
JsonTypeInfo
允许在序列化带注释的类的实例时定义额外的属性,而
JsonSubTypes
为每个子类定义该额外属性的值。在你的情况下,它看起来像这样:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "class")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Player.class, name = "player")
})

这里还有一篇来自 Baeldung 的有趣文章涵盖了该主题。

此外,由于您希望将

Player
实例存储在通用数据结构中,例如
Map
List
,因此您需要使用
TypeReference
子类化您的数据结构,以便 Jackson 知道如何正确反序列化json.

ObjectMapper mapper = new ObjectMapper();
Map<Byte, Mob> map = mapper.readValue(json, new TypeReference<Map<Byte, Mob>>() {});

这里是 OneCompiler 的链接,其中包含代码演示

© www.soinside.com 2019 - 2024. All rights reserved.