NullPointerException loading configuration after initial save

[18:15:23] [Server thread/ERROR] [Sponge]: Could not pass FMLInitializationEvent to Plugin{id=oblivioncore, name=@name@, version=@versionMajor@.@versionMinor@.@versionRevision@, source=D:\IntelliJ Workspace\SpongeForge\out\production\OblivionCore-Forge}
java.lang.NullPointerException
	at org.spongepowered.common.data.persistence.ConfigurateTranslator.translateMapOrList(ConfigurateTranslator.java:92) ~[ConfigurateTranslator.class:?]
	at org.spongepowered.common.data.persistence.ConfigurateTranslator.translateFromNode(ConfigurateTranslator.java:76) ~[ConfigurateTranslator.class:?]
	at org.spongepowered.common.data.persistence.ConfigurateTranslator.translate(ConfigurateTranslator.java:124) ~[ConfigurateTranslator.class:?]
	at org.spongepowered.common.data.persistence.ConfigurateTranslator.translate(ConfigurateTranslator.java:46) ~[ConfigurateTranslator.class:?]
	at org.spongepowered.common.config.DataSerializableTypeSerializer.deserialize(DataSerializableTypeSerializer.java:46) ~[DataSerializableTypeSerializer.class:?]
	at org.spongepowered.common.config.DataSerializableTypeSerializer.deserialize(DataSerializableTypeSerializer.java:40) ~[DataSerializableTypeSerializer.class:?]
	at ninja.leaping.configurate.objectmapping.serialize.TypeSerializers$MapSerializer.deserialize(TypeSerializers.java:165) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.objectmapping.serialize.TypeSerializers$MapSerializer.deserialize(TypeSerializers.java:143) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.objectmapping.ObjectMapper$FieldData.deserializeFrom(ObjectMapper.java:85) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.objectmapping.ObjectMapper$BoundInstance.populate(ObjectMapper.java:148) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.objectmapping.serialize.TypeSerializers$AnnotatedObjectSerializer.deserialize(TypeSerializers.java:256) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.SimpleConfigurationNode.getValue(SimpleConfigurationNode.java:226) ~[configurate-core-3.2.jar:?]
	at ninja.leaping.configurate.ConfigurationNode.getValue(ConfigurationNode.java:356) ~[configurate-core-3.2.jar:?]
	at com.oblivionnetworks.oblivioncore.common.services.config.types.datastore.FlatFileDataStore.load(FlatFileDataStore.java:58) ~[FlatFileDataStore.class:?]
	at com.oblivionnetworks.oblivioncore.common.services.config.DefaultConfigurationService.lambda$loadConfigs$0(DefaultConfigurationService.java:104) ~[DefaultConfigurationService.class:?]
	at java.util.HashMap.forEach(HashMap.java:1288) ~[?:1.8.0_101]
	at com.oblivionnetworks.oblivioncore.common.services.config.DefaultConfigurationService.loadConfigs(DefaultConfigurationService.java:100) ~[DefaultConfigurationService.class:?]
	at com.oblivionnetworks.oblivioncore.forge.Main.init(Main.java:84) ~[Main.class:?]
	at org.spongepowered.common.event.listener.GameInitializationEventListener_Main_init1.handle(Unknown Source) ~[?:?]
	at org.spongepowered.common.event.RegisteredListener.handle(RegisteredListener.java:95) ~[RegisteredListener.class:?]
	at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:301) [SpongeModEventManager.class:?]
	at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:330) [SpongeModEventManager.class:?]
	at org.spongepowered.mod.SpongeMod.onStateEvent(SpongeMod.java:201) [SpongeMod.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_101]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_101]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_101]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_101]
	at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
	at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
	at net.minecraftforge.fml.common.LoadController.sendEventToModContainer(LoadController.java:243) [LoadController.class:?]
	at net.minecraftforge.fml.common.LoadController.propogateStateMessage(LoadController.java:221) [LoadController.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_101]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_101]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_101]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_101]
	at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
	at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
	at net.minecraftforge.fml.common.LoadController.redirect$onPost$zzd000(LoadController.java:53) [LoadController.class:?]
	at net.minecraftforge.fml.common.LoadController.distributeStateMessage(LoadController.java:145) [LoadController.class:?]
	at net.minecraftforge.fml.common.Loader.initializeMods(Loader.java:807) [Loader.class:?]
	at net.minecraftforge.fml.server.FMLServerHandler.finishServerLoading(FMLServerHandler.java:108) [FMLServerHandler.class:?]
	at net.minecraftforge.fml.common.FMLCommonHandler.onServerStarted(FMLCommonHandler.java:334) [FMLCommonHandler.class:?]
	at net.minecraft.server.dedicated.DedicatedServer.init(DedicatedServer.java:218) [DedicatedServer.class:?]
	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:507) [MinecraftServer.class:?]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_101]

I’m having this NPE pop up when trying to load one of my configs, I think its something to do with the custom type serializer im using but im not exactly sure on what. Here’s the code im using:

//This is the type serializer
package com.oblivionnetworks.rustmc.api.data.serializers;

import com.google.common.reflect.TypeToken;
import com.oblivionnetworks.rustmc.api.data.type.StructureData;
import com.oblivionnetworks.rustmc.api.services.building.StructureTypes;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.objectmapping.ObjectMappingException;
import ninja.leaping.configurate.objectmapping.serialize.TypeSerializer;

import java.util.UUID;

public class StructureDataSerializer implements TypeSerializer<StructureData> {

    @Override
    public StructureData deserialize(TypeToken<?> type, ConfigurationNode value) throws ObjectMappingException {
        StructureTypes structureType = value.getNode("Type").getValue(new TypeToken<StructureTypes>() {});
        UUID owner = value.getNode("Owner").getValue(new TypeToken<UUID>() {});

        if (structureType != null && owner != null) {
            return new StructureData(structureType, owner);
        } else {
            return null;
        }
    }

    @Override
    public void serialize(TypeToken<?> type, StructureData obj, ConfigurationNode value) throws ObjectMappingException {
        value.getNode("Type").setValue(new TypeToken<StructureTypes>() {}, obj.getStructureType());
        value.getNode("Owner").setValue(new TypeToken<UUID>() {}, obj.getOwner());
    }
}

//This is the config loading/saving code
    @Override
    public OCConfig<C, N> load() {
        Preconditions.checkNotNull(config, "The config is null.");
        Preconditions.checkNotNull(configClass, "The config class is null.");
        Preconditions.checkNotNull(loader, "The configuration loader is null.");
        Preconditions.checkNotNull(path, "The config path is null.");

        if (!getPath().toFile().exists()) {
            getPath().toFile().getParentFile().mkdirs();
            saveDefaults();
        } else {
            try {
                config.setNode(getConfigurationLoader().load());
            } catch (IOException ex) {
                config.setPhase(OCConfig.Phase.ERRORED);
                ex.printStackTrace();
            }

            try {
                config.setConfig(config.getNode().getValue(TypeToken.of(getConfigClass())));
            } catch (ObjectMappingException ex) {
                config.setPhase(OCConfig.Phase.ERRORED);
                ex.printStackTrace();
            }
        }

        config.setPhase(OCConfig.Phase.LOADED);
        return config;
    }

    @Override
    public OCConfig<C, N> save() {
        try {
            config.getNode().setValue(TypeToken.of(getConfigClass()), config.get());
            getConfigurationLoader().save(config.getNode());
        } catch (IOException | ObjectMappingException ex) {
            config.setPhase(OCConfig.Phase.ERRORED);
            ex.printStackTrace();
        }

        return config;
    }

Another important note would be that the plugin handling configuration loading is another, ‘OblivionCore’ handles everything to do with configuration, loading, saving, modifying, etc. The plugin who this configuration belongs to ‘RustMC’ has a class annotated with ConfigSerializable representing the config and just has access to the instance of the object containing the configuration node once loaded but it also registers the relative type serializers. However, this is done in GamePreInitializationEvent whereas it is loaded in GameInitializationEvent

If anymore code is needed just say, I didn’t post all of at as not all is relavent and it would be a lot to dig through.

Still haven’t figured out this issue :confused:

Anyone know what could cause this?

The topmost stack element with your name on it is FlatFileDataStore; mind sharing the source for that file with us?

I think there is an issue with sponge’s ConfigurateTranslator
when translateFromNode is called with a node that has a null key (e.g. root node) it calls translateMapOrList

but it calls node.getKey().toString() resulting in an NPE

In your particular case, it’s caused by the Map serializer trying to deserialize a map’s key
https://github.com/zml2008/configurate/blob/master/configurate-core/src/main/java/ninja/leaping/configurate/objectmapping/serialize/TypeSerializers.java#L165

The error case can be tested trivially with the following code

DataTranslators.CONFIGURATION_NODE.translate(SimpleConfigurationNode.root().setValue("test"));
2 Likes

@simon816 Thanks for that great explaination :slight_smile:, what would be the best way to go about dealing with this issue? I’m unsure as to how I can change my code to deal with it.

You get an NPE as a result of trying to translate the root of the config into a map. You set the value of the root of the config, which has no key but a value now, then you try to get a map with a key -> value from the root of the config. The root of the config has no key so you get a NPE.

NullPointerExceptions are exceptions that occur when you try to use a reference that points to no location in memory (null) as though it were referencing an object. Calling a method on a null reference or trying to access a field of a null reference will trigger a NullPointerException. More about…Java NullPointerException

Balmer