[SOLVED] XML Importer not importing savable arrays

Ran into an error trying to import an array of Vector3’s

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
com.jme3.asset.AssetLoadException: An exception has occured while loading asset: Scenes/TestTerrain.j3t
	at com.jme3.asset.DesktopAssetManager.loadLocatedAsset(DesktopAssetManager.java:261)
	at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:373)
	at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:386)
	at com.mru.gothic.network.lobby.LobbyHost.<init>(LobbyHost.java:78)
	at com.mru.gothic.network.ServerState.initServer(ServerState.java:84)
	at com.mru.gothic.network.ServerState.<init>(ServerState.java:52)
	at com.mru.gothic.ui.MainMenu.hostGame(MainMenu.java:60)
	at com.mru.gothic.ui.MainMenu.lambda$initialize$0(MainMenu.java:44)
	at com.simsilica.lemur.core.CommandMap.runCommands(CommandMap.java:61)
	at com.simsilica.lemur.Button.runClick(Button.java:333)
	at com.simsilica.lemur.Button$ButtonMouseHandler.mouseButtonEvent(Button.java:410)
	at com.simsilica.lemur.event.MouseEventControl.mouseButtonEvent(MouseEventControl.java:122)
	at com.simsilica.lemur.event.PickEventSession.buttonEvent(PickEventSession.java:624)
	at com.simsilica.lemur.event.MouseAppState.dispatch(MouseAppState.java:98)
	at com.simsilica.lemur.event.MouseAppState$MouseObserver.onMouseButtonEvent(MouseAppState.java:114)
	at com.jme3.input.InputManager.processQueue(InputManager.java:831)
	at com.jme3.input.InputManager.update(InputManager.java:907)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:725)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:227)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: java.lang.ClassCastException: [Lcom.jme3.export.Savable; cannot be cast to [Lcom.jme3.math.Vector3f;
	at com.jme3.export.xml.DOMInputCapsule.readSavable(DOMInputCapsule.java:956)
	at com.jme3.export.xml.XMLImporter.load(XMLImporter.java:99)
	at com.jme3.export.xml.XMLImporter.load(XMLImporter.java:78)
	at com.jme3.asset.DesktopAssetManager.loadLocatedAsset(DesktopAssetManager.java:259)
	... 22 more
Caused by: java.lang.ClassCastException: [Lcom.jme3.export.Savable; cannot be cast to [Lcom.jme3.math.Vector3f;
	at com.mru.gothic.scene.Scene.read(Scene.java:92)
	at com.jme3.export.xml.DOMInputCapsule.readSavableFromCurrentElem(DOMInputCapsule.java:1002)
	at com.jme3.export.xml.DOMInputCapsule.readSavable(DOMInputCapsule.java:947)
	... 25 more

and the code

@Override
    public void read(JmeImporter im) throws IOException {
        InputCapsule in = im.getCapsule(this);
        heightMap = in.readString("HEIGHTMAP", null);
        preview = in.readString("PREVIEW", null);
        height = in.readFloat("TERRAINHEIGHT", Float.MIN_VALUE);
        waterHeight = in.readFloat("WATERHEIGHT", Float.MIN_VALUE);
        spawns = (Vector3f[])in.readSavableArray("SPAWNS", null);
    }

and the xml

<?xml  version='1.0' encoding='UTF-8'?>
<com.mru.gothic.scene.Scene HEIGHTMAP='Textures/HeightMaps/TestMap.png' TERRAINHEIGHT='0.06037' WATERHEIGHT='195.15' format_version='2' savable_versions='0'>
    <SPAWNS size='2'>
        <com.jme3.math.Vector3f savable_versions='0' x='1.0' y='1.0' z='1.0'/>
        <com.jme3.math.Vector3f savable_versions='0' x='-1.0' y='1.0' z='-1.0'/>
    </SPAWNS>
</com.mru.gothic.scene.Scene>

Any idea on why a Vector3f isn’t getting cast to Savable? I’ve had similar issues in the past which were fixed by using the binary exporter/importer, but I really need a human readable file format for these files so I can edit them by hand instead of writing an editor from scratch.

Which version of jME are you using?

Can you try a test like: spawns[0] instanceof Vector3f?
Because if these Vectors would get serialized as Savables instead of Vector3fs, they can’t be cast.
Another idea would maybe be checking if you can cast them item-by-item instead of the whole array at once.

Technically, it’s importing them… but it’s importing them as a Savable[] array because it has no idea what type to actually create.

If you use List to save/load then I think you get a little more flexibility since generics are only a compile-time constraint. Arrays are a runtime constraint.

Also, I don’t know if the read() call is smart enough to do the right thing if you pass a default value like new Vector3f[0]… I suspect not. But that’s the way I’d have written it. :slight_smile:

Thanks a ton @pspeed & @Darkchaos! You were right that it wasn’t casting the array, I thought it wasn’t casting the array’s objects. Here’s a work around for anyone else who has a similar issue.

Savable[] spawnArray = in.readSavableArray("SPAWNS", null);`
spawns = new Vector3f[spawnArray.length];
for(int x=0; x<spawnArray.length; x++){
    spawns[x] = (Vector3f)spawnArray[x];
}