3

I am trying to create a Java program that reads and writes complex objects to and from a MongoDB, for example...

public class GameCharacter {
    public String name;
    public Weapon weapon;
    public Armor armor;

    public GameCharacter(String name, Weapon weapon, Armor armor) {
        this.name = name;
        this.weapon = weapon;
        this.armor = armor;
    }
}

I have managed to write it by setting this codec, and I can check in the database that all the data is correctly written in the right structure:

        CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
        PojoCodecProvider pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
        CodecRegistry pojoCodecRegistry = fromRegistries(defaultCodecRegistry, fromProviders(pojoCodecProvider));

        MongoDatabase characterDatabase = mongoDatabaseConnectionPool.getDatabase(CHARACTER_DATABASE_NAME);
        characterDatabase = characterDatabase.withCodecRegistry(pojoCodecRegistry);
        MongoCollection<GameCharacter> characterCollection = characterDatabase.getCollection(CHARACTER_COLLECTION_NAME, GameCharacter.class);

        Character testCharacter = new Character ("Sylvia Zerin", testWeapon, testArmor);
        characterCollection.insertOne(testCharacter);

...however, when trying to read the GameCharacter from that database again like this:

        FindIterable<GameCharacter> characters = characterCollection.find();

...then the following error message appears:

org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'GameCharacter' failed with the following exception:

Cannot find a public constructor for 'GameCharacter'.

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.

This is confusing for me, since I provided a public constructor for the GameCharacter class. It is not clear to me why the program fails to find it.

Following the answer in this question, I have also tried the following to set the codec:

        ClassModel<GameCharacter> gameCharacterClassModel = ClassModel.builder(GameCharacter.class).enableDiscriminator(true).build();


        CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
        CodecRegistry pojoCodecRegistry = fromRegistries(defaultCodecRegistry, fromProviders(PojoCodecProvider.builder().register(gameCharacterClassModel).automatic(true).build()));
        return pojoCodecRegistry;

...however, that only slightly changes the error message to:

org.bson.codecs.configuration.CodecConfigurationException: Cannot find a public constructor for 'GameCharacter'.

What do I have to do in order to be able to retrieve the GameCharacterObject from the MongoDB again?

Kira Resari
  • 1,718
  • 4
  • 19
  • 50

1 Answers1

7

I figured it out.

The error message is somewhat misleading. Actually, the problem is that it needs an empty constructor without arguments, so naturally the constructor in my class above will not work. The exact requirements as defined here are as follows:

By default all POJOs must include a public or protected, empty, no arguments, constructor.

Thus, the problem can be solved by changing the GameCharacter class to look as follows:

public class GameCharacter {
    public String name;
    public Weapon weapon;
    public Armor armor;

    public GameCharacter() {
    }

    public GameCharacter(String name, Weapon weapon, Armor armor) {
        this.name = name;
        this.weapon = weapon;
        this.armor = armor;
    }
}
Kira Resari
  • 1,718
  • 4
  • 19
  • 50