[JAVA-2754] using multiple marks on reader causes errors Created: 28/Jan/18  Updated: 28/Oct/23  Resolved: 30/Jan/18

Status: Closed
Project: Java Driver
Component/s: BSON
Affects Version/s: 3.5.0, 3.6.0
Fix Version/s: 3.7.0

Type: Bug Priority: Major - P3
Reporter: Michael Weber Assignee: Jeffrey Yemin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

mac os, jdk 1.8.0_144


Issue Links:
Related
is related to JAVA-2416 BSONReader mark - add support to unse... Closed

 Description   

In JAVA-2416 support to set multiple marks on BsonReader was added.
Unfortunately I have trouble using these.
It's somehow hard to explain the observed behaviour and it might even be the case I misunderstand the implemented logic.

Have a look at the following simple java program.
It is expected to work as follows:

  1. A Pojo is created and persisted in the database. -> this works fine
  2. The Codec for Pojo (PojoCodec) should decode this entity -> doe not work

Decoding explained:
A marker is retrieved from the reader. When something goes wrong (exception) the reader should backoff (mark.reset()) and the current entitiy skipped. This does actually work fine.
If now, a second marker is set on the reader, things do not work any longer.
After resetting the first marker a call to reader.skipValue() will throw the following exception:

Exception in thread "main" java.lang.IllegalArgumentException
	at java.nio.Buffer.position(Buffer.java:244)
	at org.bson.ByteBufNIO.position(ByteBufNIO.java:118)

Here the program to reproduce the behaviour.

 
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import org.bson.BsonReader;
import org.bson.BsonReaderMark;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.types.ObjectId;
 
public class MarkerTest {
 
    CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new PojoCodec());
 
    static class Pojo {
        ObjectId id;
        String stringField;
 
        public String getStringField() {
            return stringField;
        }
 
        public void setStringField(String stringField) {
            this.stringField = stringField;
        }
 
        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("Pojo{");
            sb.append("id=").append(id);
            sb.append(", stringField='").append(stringField).append('\'');
            sb.append('}');
            return sb.toString();
        }
    }
 
 
    /**
     * Resilient codec that skips entities, in case of exceptions during decoding
     */
    static class PojoCodec implements Codec<Pojo> {
        @Override
        public Pojo decode(BsonReader reader, DecoderContext decoderContext) {
            Pojo pojo = null;
            BsonReaderMark mark = null;
 
            try {
                mark = reader.getMark();
                reader.readStartDocument();
                pojo = new Pojo();
                // reading fields and set in Pojo
                pojo.setStringField(readFields(reader));
                reader.readEndDocument();
                return pojo;
 
            } catch (Exception e) {
                System.out.println(e);
                mark.reset();
                reader.skipValue();
            }
            return pojo;
        }
 
        private String readFields(BsonReader reader) {
            // the following mark, even if never needed, causes the above mark.reset() to reset the reader to the wrong position
            BsonReaderMark markInReadingFields = reader.getMark();
 
            reader.readName();
            reader.readObjectId();
            //simulate random decoding exception....
            if (true) throw new RuntimeException("Some random exception occurred");
            reader.readName();
            return reader.readString();
        }
 
        @Override
        public void encode(BsonWriter writer, Pojo pojo, EncoderContext encoderContext) {
            writer.writeStartDocument();
            writer.writeName("stringField");
            writer.writeString(pojo.getStringField());
            writer.writeEndDocument();
        }
 
        @Override
        public Class<Pojo> getEncoderClass() {
            return Pojo.class;
        }
    }
 
    public void testMultipleMarker() {
 
        MongoClientOptions mongoClientOptions = new MongoClientOptions.Builder().codecRegistry(codecRegistry).build();
        MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017), mongoClientOptions);
 
        Pojo pojo = new Pojo();
        pojo.setStringField("test");
        System.out.println("Pojo = " + pojo);
 
        MongoCollection<Pojo> pojoMongoCollection = mongoClient.getDatabase("test").getCollection("pojos").withDocumentClass(Pojo.class);
        pojoMongoCollection.insertOne(pojo);
 
        Pojo readPojo = pojoMongoCollection.find().first();
        System.out.println("Decoded pojo = " + readPojo);
    }
 
    public static void main(String[] args) {
        new MarkerTest().testMultipleMarker();
    }
}



 Comments   
Comment by Githook User [ 30/Jan/18 ]

Author:

{'email': 'jeff.yemin@10gen.com', 'name': 'Jeff Yemin', 'username': 'jyemin'}

Message: JAVA-2754: Support multiple marks on BsonInput, and use that to fix bug in support for multiple marks on a BsonBinaryReader
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/9df58fee27d17a4aa601e82240f718ee9a662d40

Comment by Michael Weber [ 28/Jan/18 ]

One more note:
In other scenarios with different nestings of markers I observe different errors.

E.g. the following:

Caused by: org.bson.BsonSerializationException: Expected size to be 112, not 111.
	at org.bson.BsonBinaryReader$Context.popContext(BsonBinaryReader.java:445)

In that example, the mark was reset() but somehow the reader seems to be left in a wrong state.

Generated at Thu Feb 08 08:57:59 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.