Uploaded image for project: 'Java Driver'
  1. Java Driver
  2. JAVA-4927

Null property during serialization breaks deserialization with @BsonCreator

    • Type: Icon: Bug Bug
    • Resolution: Unresolved
    • Priority: Icon: Minor - P4 Minor - P4
    • None
    • Affects Version/s: 4.9.1
    • Component/s: POJO
    • None

      Summary

      If a POJO containing null fields is serialised, the resulting document does not have those null fields. During deserialisation of said document with @BsonCreator, an exception is thrown due to a missing property. 

      How to Reproduce

      1. This is the POJO class I used
        package database;
        import org.bson.codecs.pojo.annotations.*;
        import org.bson.types.ObjectId;
        public class User {
            
            @BsonId
            private final ObjectId objectId;
            private final long id;
            private final UserPreferences preferences;
            private String favColour;
            
            @BsonCreator
            public User(@BsonId ObjectId objectId,
            @BsonProperty long id, 
            @BsonProperty("preferences") UserPreferences preferences,                                                                                             
            @BsonProperty("favColour") String favColour) {
                this.objectId = objectId;
                this.id = id;
                this.preferences = preferences;
                this.favColour = favColour;
            }    
            public ObjectId getObjectId() {
                return objectId;
            }    
            public long getId() {
                return id;
            }
            
            public UserPreferences getPreferences() {
                return preferences;
            }    
            public String getFavColour() {
                return favColour;
            }    
            public void setFavColour(String favColour) {
                this.favColour = favColour;
            }
            
        }
         
      1. The POJO was instantiated like this
        new User(null, 743234737894L, new UserPreferences().setPresence(false), null) 

        The first null parameter is fine as ObjectId is auto generated by the driver. The last null parameter sets favColour to null so it is ignored during serialisation but throws an exception during deserialisation.

      1. The following exception is thrown.
        Exception in thread "main" org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when decoding using the AutomaticPojoCodec.
        Decoding into a 'User' failed with the following exception:
        
        Could not construct new instance of: User. 
        Missing the following properties: [, favColour]
        
        A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
            at org.bson.codecs.pojo.AutomaticPojoCodec.decode(AutomaticPojoCodec.java:40)
            at com.mongodb.internal.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
            at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:60)
            at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
            at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
            at org.bson.internal.LazyCodec.decode(LazyCodec.java:53)
            at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:104)
            at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
            at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
            at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
            at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:48)
            at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:560)
            at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:450)
            at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:365)
            at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:114)
            at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:643)
            at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:73)
            at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:204)
            at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:122)
            at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:87)
            at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:76)
            at com.mongodb.internal.connection.DefaultServer$OperationCountTrackingConnection.command(DefaultServer.java:288)
            at com.mongodb.internal.operation.CommandOperationHelper.createReadCommandAndExecute(CommandOperationHelper.java:239)
            at com.mongodb.internal.operation.FindOperation.lambda$execute$1(FindOperation.java:326)
            at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$0(OperationHelper.java:358)
            at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:383)
            at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$1(OperationHelper.java:357)
            at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:383)
            at com.mongodb.internal.operation.OperationHelper.withSourceAndConnection(OperationHelper.java:356)
            at com.mongodb.internal.operation.FindOperation.lambda$execute$2(FindOperation.java:323)
            at com.mongodb.internal.async.function.RetryingSyncSupplier.get(RetryingSyncSupplier.java:67)
            at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:334)
            at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:73)
            at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:185)
            at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:213)
            at database.DBTest.test(DBTest.java:27)
            at main.FourTenBot.main(FourTenBot.java:106)
        Caused by: org.bson.codecs.configuration.CodecConfigurationException: Could not construct new instance of: User. Missing the following properties: [, favColour]
            at org.bson.codecs.pojo.InstanceCreatorImpl.getInstance(InstanceCreatorImpl.java:94)
            at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:113)
            at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:116)
            at org.bson.codecs.pojo.AutomaticPojoCodec.decode(AutomaticPojoCodec.java:37)
            ... 36 more
        Caused by: org.bson.codecs.configuration.CodecConfigurationException
            at org.bson.codecs.pojo.InstanceCreatorImpl.constructInstanceAndProcessCachedValues(InstanceCreatorImpl.java:106)
            at org.bson.codecs.pojo.InstanceCreatorImpl.getInstance(InstanceCreatorImpl.java:92)
            ... 39 more
        Caused by: org.bson.codecs.configuration.CodecConfigurationException
            at org.bson.codecs.pojo.CreatorExecutable.getInstance(CreatorExecutable.java:129)
            at org.bson.codecs.pojo.InstanceCreatorImpl.constructInstanceAndProcessCachedValues(InstanceCreatorImpl.java:104)
            ... 40 more
        Caused by: java.lang.IllegalArgumentException
            at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
            at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
            at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
            at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
            at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
            at org.bson.codecs.pojo.CreatorExecutable.getInstance(CreatorExecutable.java:124)
            ... 41 more 

      Additional Background

      This issue was previously resolved in #JAVA-2587 but it seems it has been reintroduced in a later version.

            Assignee:
            Unassigned Unassigned
            Reporter:
            dennisnwanevu@gmail.com Dennis NCO
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: