junkdog / artemis-odb

A continuation of the popular Artemis ECS framework
BSD 2-Clause "Simplified" License
769 stars 109 forks source link

Serialization of LinkedHashMap<Integer, Integer> #630

Closed bryanbrunt closed 3 years ago

bryanbrunt commented 3 years ago

Unserializing the following Component will result in a LinkedHashMap<String, Integer> instead of a LinkedHashMap<Integer, Integer>.

public class Skills extends Component { public LinkedHashMap<Integer, Integer> skills = new LinkedHashMap<Integer, Integer>();
}

DaanVanYperen commented 3 years ago

Which serializer module are you using in your project? Providing a small example project that shows the issue will help speed up the process.

DaanVanYperen commented 3 years ago

Hi @bryanbrunt! Unfortunately this would be a bit of a pickle to fix. Luckily there is a workaround available, us LibGDX IntMap (or Kryo backend),

Reproduced in both artemis and libgdx json backends. Key type is not stored in Json which effectively makes it a String. To fix it should be coerced on read: https://github.com/libgdx/libgdx/blob/f27c5685262c3ee55fa9c0267e73de021e6d4b93/gdx/src/com/badlogic/gdx/utils/Json.java#L1075

LibGDX background: https://github.com/libgdx/libgdx/issues/2693

Test

class CustomJsonWorldSerializationManagerTest {

    @Test
    public void linkedhashmap_retains_generics_on_serialization() throws Exception {

        deleteAll();
        EntityEdit ee = world.createEntity().edit();
        ee.create(LinkedHashMapComponent.class).skills.put(1,1);
        world.process();
        assertEquals(1, allEntities.getEntities().size());
        String json = save(allEntities, "a string", 420);
        deleteAll();
        ByteArrayInputStream is = new ByteArrayInputStream(
                json.getBytes("UTF-8"));
        SaveFileFormat load = manger.load(is, SaveFileFormat.class);
        world.process();

        Bag components = world.getComponentManager().getComponentsFor(allEntities.getEntities().get(0), new Bag());
        assertEquals(new Integer(1),((LinkedHashMapComponent)components.get(0)).skills.keySet().iterator().next());
    }

Json

"entities": {
    "0": {
        "archetype": 1,
        "components": {
            "LinkedHashMapComponent": {
                "skills": {
                    "1": 1
                }
            }
        }
    }
DaanVanYperen commented 3 years ago

Closing this as Will Not Fix as there is a workaround available and the fix is expensive.