[JAVA-4927] Null property during serialization breaks deserialization with @BsonCreator Created: 08/Apr/23  Updated: 17/Apr/23

Status: Backlog
Project: Java Driver
Component/s: POJO
Affects Version/s: 4.9.1
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Dennis NCO Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to JAVA-2587 Null property during serialization br... Closed

 Description   

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.



 Comments   
Comment by Jeffrey Yemin [ 10/Apr/23 ]

dennisnwanevu@gmail.com glad you found a workaround to unblock you, but it still seems like a bug so putting it in the backlog.

Thanks for reporting this and also for following up with your solution.

Comment by Dennis NCO [ 08/Apr/23 ]

 

    @BsonCreator
    public User(@BsonId ObjectId objectId, 
        @BsonProperty("id") long id, 
        @BsonProperty("preferences") UserPreferences preferences, 
        @BsonProperty("favColour") String favColour) {
        this.objectId = objectId;
        this.id = id;
        this.preferences = preferences;
        this.favColour = favColour;
    }

Okay so it turns out I just had to add 

@BsonProperty("id") long id

Not sure why that affected the deserialisation of favColour but I guess the issue is resolved now.

 

 

Generated at Thu Feb 08 09:03:18 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.