Skip to content

Commit

Permalink
JAVA-2197: In ByteBufBsonDocument use internal Finder interface to im…
Browse files Browse the repository at this point in the history
…plement the size method
  • Loading branch information
jyemin committed Jun 6, 2016
1 parent d98c9cd commit 79a6e93
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 22 deletions.
5 changes: 5 additions & 0 deletions config/findbugs-exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,9 @@
<Bug pattern="RANGE_ARRAY_INDEX"/>
</Match>

<Match>
<Class name="~com.mongodb.connection.ByteBufBsonDocument.*"/>
<Bug pattern="NP_BOOLEAN_RETURN_NULL"/>
</Match>

</FindBugsFilter>
Original file line number Diff line number Diff line change
Expand Up @@ -122,30 +122,34 @@ public boolean isEmpty() {
return findInDocument(new Finder<Boolean>() {
@Override
public Boolean find(final BsonReader bsonReader) {
return bsonReader.getCurrentBsonType() == BsonType.END_OF_DOCUMENT;
return false;
}
}, true);

@Override
public Boolean notFound() {
return true;
}
});
}

@Override
public int size() {
int size = 0;
final ByteBuf duplicateByteBuf = byteBuf.duplicate();
BsonBinaryReader bsonReader = new BsonBinaryReader(new ByteBufferBsonInput(duplicateByteBuf));
try {
bsonReader.readStartDocument();
while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
return findInDocument(new Finder<Integer>() {
private int size;

@Override
public Integer find(final BsonReader bsonReader) {
size++;
bsonReader.readName();
bsonReader.skipValue();
return null;
}
bsonReader.readEndDocument();
} finally {
duplicateByteBuf.release();
bsonReader.close();
}

return size;
@Override
public Integer notFound() {
return size;
}
});
}

@Override
Expand Down Expand Up @@ -178,7 +182,12 @@ public Boolean find(final BsonReader bsonReader) {
bsonReader.skipValue();
return null;
}
}, false);

@Override
public Boolean notFound() {
return false;
}
});
}

@Override
Expand All @@ -192,7 +201,12 @@ public Boolean find(final BsonReader bsonReader) {
}
return null;
}
}, false);

@Override
public Boolean notFound() {
return false;
}
});
}

@Override
Expand All @@ -210,7 +224,12 @@ public BsonValue find(final BsonReader bsonReader) {
bsonReader.skipValue();
return null;
}
}, null);

@Override
public BsonValue notFound() {
return null;
}
});
}

@Override
Expand Down Expand Up @@ -244,14 +263,20 @@ public String getFirstKey() {
public String find(final BsonReader bsonReader) {
return bsonReader.readName();
}
}, null);

@Override
public String notFound() {
return null;
}
});
}

private interface Finder<T> {
T find(BsonReader bsonReader);
T notFound();
}

private <T> T findInDocument(Finder<T> finder, T defaultValueIfNotFound) {
private <T> T findInDocument(final Finder<T> finder) {
ByteBuf duplicateByteBuf = byteBuf.duplicate();
BsonBinaryReader bsonReader = new BsonBinaryReader(new ByteBufferBsonInput(duplicateByteBuf));
try {
Expand All @@ -268,7 +293,7 @@ private <T> T findInDocument(Finder<T> finder, T defaultValueIfNotFound) {
bsonReader.close();
}

return defaultValueIfNotFound;
return finder.notFound();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.bson.BsonDocument
import org.bson.BsonInt32
import org.bson.BsonNull
import org.bson.BsonValue
import org.bson.ByteBuf
import org.bson.ByteBufNIO
import org.bson.codecs.BsonDocumentCodec
import org.bson.codecs.EncoderContext
Expand All @@ -37,7 +38,9 @@ import static java.util.Arrays.asList
import static util.GroovyHelpers.areEqual

class ByteBufBsonDocumentSpecification extends Specification {
ByteBufBsonDocument emptyRawDocument = new ByteBufBsonDocument(new ByteBufNIO(ByteBuffer.wrap([5, 0, 0, 0, 0] as byte[])));
def emptyDocumentByteBuf = new ByteBufNIO(ByteBuffer.wrap([5, 0, 0, 0, 0] as byte[]))
ByteBuf documentByteBuf
ByteBufBsonDocument emptyRawDocument = new ByteBufBsonDocument(emptyDocumentByteBuf);
def document = new BsonDocument()
.append('a', new BsonInt32(1))
.append('b', new BsonInt32(2))
Expand All @@ -49,7 +52,10 @@ class ByteBufBsonDocumentSpecification extends Specification {
def setup() {
def buffer = new BasicOutputBuffer()
new BsonDocumentCodec().encode(new BsonBinaryWriter(buffer), document, EncoderContext.builder().build());
rawDocument = new ByteBufBsonDocument(new CompositeByteBuf(buffer.byteBuffers));
ByteArrayOutputStream baos = new ByteArrayOutputStream()
buffer.pipe(baos)
documentByteBuf = new ByteBufNIO(ByteBuffer.wrap(baos.toByteArray()))
rawDocument = new ByteBufBsonDocument(documentByteBuf);
}

def 'get should get the value of the given key'() {
Expand All @@ -67,6 +73,7 @@ class ByteBufBsonDocumentSpecification extends Specification {

then:
thrown(IllegalArgumentException)
documentByteBuf.referenceCount == 1
}

def 'containKey should throw if the key name is null'() {
Expand All @@ -75,6 +82,7 @@ class ByteBufBsonDocumentSpecification extends Specification {

then:
thrown(IllegalArgumentException)
documentByteBuf.referenceCount == 1
}

def 'containsKey should find an existing key'() {
Expand All @@ -83,13 +91,15 @@ class ByteBufBsonDocumentSpecification extends Specification {
rawDocument.containsKey('b')
rawDocument.containsKey('c')
rawDocument.containsKey('d')
documentByteBuf.referenceCount == 1
}

def 'containsKey should not find a non-existing key'() {
expect:
!rawDocument.containsKey('e')
!rawDocument.containsKey('x')
!rawDocument.containsKey('y')
documentByteBuf.referenceCount == 1
}

def 'containValue should find an existing value'() {
Expand All @@ -98,41 +108,51 @@ class ByteBufBsonDocumentSpecification extends Specification {
rawDocument.containsValue(document.get('b'))
rawDocument.containsValue(document.get('c'))
rawDocument.containsValue(document.get('d'))
documentByteBuf.referenceCount == 1
}

def 'containValue should not find a non-existing value'() {
expect:
!rawDocument.containsValue(new BsonInt32(3))
!rawDocument.containsValue(new BsonDocument('e', BsonBoolean.FALSE))
!rawDocument.containsValue(new BsonArray(asList(new BsonInt32(2), new BsonInt32(4))))
documentByteBuf.referenceCount == 1
}

def 'isEmpty should return false when the document is not empty'() {
expect:
!rawDocument.isEmpty()
documentByteBuf.referenceCount == 1
}

def 'isEmpty should return true when the document is empty'() {
expect:
emptyRawDocument.isEmpty()
emptyDocumentByteBuf.referenceCount == 1
}

def 'should get correct size'() {
expect:
emptyRawDocument.size() == 0
rawDocument.size() == 4
documentByteBuf.referenceCount == 1
emptyDocumentByteBuf.referenceCount == 1
}

def 'should get correct key set'() {
expect:
emptyRawDocument.keySet().isEmpty()
rawDocument.keySet() == ['a', 'b', 'c', 'd'] as Set
documentByteBuf.referenceCount == 1
emptyDocumentByteBuf.referenceCount == 1
}

def 'should get correct values set'() {
expect:
emptyRawDocument.values().isEmpty()
rawDocument.values() as Set == [document.get('a'), document.get('b'), document.get('c'), document.get('d')] as Set
documentByteBuf.referenceCount == 1
emptyDocumentByteBuf.referenceCount == 1
}

def 'should get correct entry set'() {
Expand All @@ -142,6 +162,8 @@ class ByteBufBsonDocumentSpecification extends Specification {
new TestEntry('b', document.get('b')),
new TestEntry('c', document.get('c')),
new TestEntry('d', document.get('d'))] as Set
documentByteBuf.referenceCount == 1
emptyDocumentByteBuf.referenceCount == 1
}

def 'all write methods should throw UnsupportedOperationException'() {
Expand Down Expand Up @@ -180,11 +202,14 @@ class ByteBufBsonDocumentSpecification extends Specification {
expect:
rawDocument.getFirstKey() == document.keySet().iterator().next()
emptyRawDocument.getFirstKey() == null
documentByteBuf.referenceCount == 1
emptyDocumentByteBuf.referenceCount == 1
}

def 'hashCode should equal hash code of identical BsonDocument'() {
expect:
rawDocument.hashCode() == document.hashCode()
documentByteBuf.referenceCount == 1
}

def 'equals should equal identical BsonDocument'() {
Expand All @@ -193,6 +218,7 @@ class ByteBufBsonDocumentSpecification extends Specification {
areEqual(document, rawDocument)
areEqual(rawDocument, rawDocument)
!areEqual(rawDocument, emptyRawDocument)
documentByteBuf.referenceCount == 1
}

def 'clone should make a deep copy'() {
Expand All @@ -201,6 +227,7 @@ class ByteBufBsonDocumentSpecification extends Specification {

then:
cloned == rawDocument
documentByteBuf.referenceCount == 1
}

def 'should serialize and deserialize'() {
Expand All @@ -216,17 +243,27 @@ class ByteBufBsonDocumentSpecification extends Specification {

then:
rawDocument == deserializedDocument
documentByteBuf.referenceCount == 1
}

def 'toJson should return equivalent'() {
expect:
document.toJson() == rawDocument.toJson()
documentByteBuf.referenceCount == 1
}

def 'toJson should be callable multiple times'() {
expect:
rawDocument.toJson()
rawDocument.toJson()
documentByteBuf.referenceCount == 1
}

def 'size should be callable multiple times'() {
expect:
rawDocument.size()
rawDocument.size()
documentByteBuf.referenceCount == 1
}

def 'toJson should respect JsonWriteSettings'() {
Expand Down

0 comments on commit 79a6e93

Please sign in to comment.