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

using multiple marks on reader causes errors

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 3.7.0
    • Affects Version/s: 3.5.0, 3.6.0
    • Component/s: BSON
    • None
    • Environment:
      mac os, jdk 1.8.0_144

      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();
          }
      }
      

            Assignee:
            jeff.yemin@mongodb.com Jeffrey Yemin
            Reporter:
            michael.weber@bild.de Michael Weber
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: