Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 13 additions & 38 deletions src/MongoDB.Bson/BsonDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,71 +24,46 @@ namespace MongoDB.Bson
/// </summary>
public static class BsonDefaults
{
// private static fields
private static bool __dynamicArraySerializerWasSet;
private static IBsonSerializer __dynamicArraySerializer;
private static bool __dynamicDocumentSerializerWasSet;
private static IBsonSerializer __dynamicDocumentSerializer;
private static int __maxDocumentSize = int.MaxValue;
private static int __maxSerializationDepth = 100;

// public static properties
/// <summary>
/// Gets or sets the dynamic array serializer.
/// </summary>
public static IBsonSerializer DynamicArraySerializer
{
get
{
if (!__dynamicArraySerializerWasSet)
{
__dynamicArraySerializer = BsonSerializer.LookupSerializer<List<object>>();
}
return __dynamicArraySerializer;
}
set
{
__dynamicArraySerializerWasSet = true;
__dynamicArraySerializer = value;
}
get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for this class to be immutable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could when we have builders and we'll have only setters.

set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer = value;
}

/// <summary>
/// Gets or sets the dynamic document serializer.
/// </summary>
public static IBsonSerializer DynamicDocumentSerializer
{
get
{
if (!__dynamicDocumentSerializerWasSet)
{
__dynamicDocumentSerializer = BsonSerializer.LookupSerializer<ExpandoObject>();
}
return __dynamicDocumentSerializer;
}
set
{
__dynamicDocumentSerializerWasSet = true;
__dynamicDocumentSerializer = value;
}
get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer;
set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer = value;
}

/* DOMAIN-API We should modify the API to have those two values (and in the writer/reader settings where they are used) be nullable.
* The problem is that we need to now when these values have been set externally or not. If they have not, then they should
* be retrieved from the closest domain.
*/

/// <summary>
/// Gets or sets the default max document size. The default is 4MiB.
/// </summary>
public static int MaxDocumentSize
{
get { return __maxDocumentSize; }
set { __maxDocumentSize = value; }
get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize;
set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize = value;
}

/// <summary>
/// Gets or sets the default max serialization depth (used to detect circular references during serialization). The default is 100.
/// </summary>
public static int MaxSerializationDepth
{
get { return __maxSerializationDepth; }
set { __maxSerializationDepth = value; }
get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth;
set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth = value;
}
}
}
73 changes: 73 additions & 0 deletions src/MongoDB.Bson/BsonDefaultsDomain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System.Collections.Generic;
using System.Dynamic;
using MongoDB.Bson.Serialization;

namespace MongoDB.Bson
{
internal class BsonDefaultsDomain : IBsonDefaults
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for this class to be immutable?
Also do we need to maintain Defaults entities under domain, as opposed to just Settings (which are initialized to defaults)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, we can decide to make this immutable when this is created with builders.
Regarding the second point, would you like the class to be renamed to Settings and initialize those from BsonDefaults that are kept static?

{
private IBsonSerializationDomain _serializationDomain;
private bool _dynamicArraySerializerWasSet;
private IBsonSerializer _dynamicArraySerializer;
private bool _dynamicDocumentSerializerWasSet;
private IBsonSerializer _dynamicDocumentSerializer;

public BsonDefaultsDomain(IBsonSerializationDomain serializationDomain)
{
_serializationDomain = serializationDomain;
}

public IBsonSerializer DynamicArraySerializer
{
get
{
if (!_dynamicArraySerializerWasSet)
{
_dynamicArraySerializer = _serializationDomain.LookupSerializer<List<object>>();
}
return _dynamicArraySerializer;
}
set
{
_dynamicArraySerializerWasSet = true;
_dynamicArraySerializer = value;
}
}

public IBsonSerializer DynamicDocumentSerializer
{
get
{
if (!_dynamicDocumentSerializerWasSet)
{
_dynamicDocumentSerializer = _serializationDomain.LookupSerializer<ExpandoObject>();
}
return _dynamicDocumentSerializer;
}
set
{
_dynamicDocumentSerializerWasSet = true;
_dynamicDocumentSerializer = value;
}
}

public int MaxDocumentSize { get; set; } = int.MaxValue;

public int MaxSerializationDepth { get; set; } = 100;
}
}
67 changes: 54 additions & 13 deletions src/MongoDB.Bson/BsonExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace MongoDB.Bson
/// </summary>
public static class BsonExtensionMethods
{
//DOMAIN-API We should remove all the methods that do not take a serialization domain.
//QUESTION: Do we want to do something now about this...? The methods are also used internally, but it seems in most cases it's used for "default serialization" and for "ToString" methods, so it should be ok.
/// <summary>
/// Serializes an object to a BSON byte array.
/// </summary>
Expand All @@ -41,12 +43,21 @@ public static byte[] ToBson<TNominalType>(
IBsonSerializer<TNominalType> serializer = null,
BsonBinaryWriterSettings writerSettings = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs),
BsonSerializationArgs args = default,
int estimatedBsonSize = 0) => ToBson(obj, BsonSerializer.DefaultSerializationDomain, serializer, writerSettings, configurator, args, estimatedBsonSize);

private static byte[] ToBson<TNominalType>(
this TNominalType obj,
IBsonSerializationDomain serializationDomain,
IBsonSerializer<TNominalType> serializer = null,
BsonBinaryWriterSettings writerSettings = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default,
int estimatedBsonSize = 0)
{
args.SetOrValidateNominalType(typeof(TNominalType), "<TNominalType>");

return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize);
return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize);
}

/// <summary>
Expand All @@ -68,7 +79,18 @@ public static byte[] ToBson(
BsonBinaryWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs),
BsonSerializationArgs args = default,
int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings,
serializer, configurator, args, estimatedBsonSize);

private static byte[] ToBson(
this object obj,
Type nominalType,
IBsonSerializationDomain serializationDomain,
BsonBinaryWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default,
int estimatedBsonSize = 0)
{
if (estimatedBsonSize < 0)
Expand All @@ -84,7 +106,7 @@ public static byte[] ToBson(

if (serializer == null)
{
serializer = BsonSerializer.LookupSerializer(nominalType);
serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
Expand All @@ -96,7 +118,7 @@ public static byte[] ToBson(
{
using (var bsonWriter = new BsonBinaryWriter(memoryStream, writerSettings ?? BsonBinaryWriterSettings.Defaults))
{
var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator);
serializer.Serialize(context, args, obj);
}
return memoryStream.ToArray();
Expand All @@ -116,7 +138,7 @@ public static BsonDocument ToBsonDocument<TNominalType>(
this TNominalType obj,
IBsonSerializer<TNominalType> serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
BsonSerializationArgs args = default)
{
args.SetOrValidateNominalType(typeof(TNominalType), "<TNominalType>");
return ToBsonDocument(obj, typeof(TNominalType), serializer, configurator, args);
Expand All @@ -138,7 +160,16 @@ public static BsonDocument ToBsonDocument(
Type nominalType,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
BsonSerializationArgs args = default) => ToBsonDocument(obj, nominalType,
BsonSerializer.DefaultSerializationDomain, serializer, configurator, args);

private static BsonDocument ToBsonDocument(
this object obj,
Type nominalType,
IBsonSerializationDomain serializationDomain,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default)
{
if (nominalType == null)
{
Expand All @@ -165,7 +196,7 @@ public static BsonDocument ToBsonDocument(
return convertibleToBsonDocument.ToBsonDocument(); // use the provided ToBsonDocument method
}

serializer = BsonSerializer.LookupSerializer(nominalType);
serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
Expand All @@ -177,7 +208,7 @@ public static BsonDocument ToBsonDocument(
var document = new BsonDocument();
using (var bsonWriter = new BsonDocumentWriter(document))
{
var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator);
serializer.Serialize(context, args, obj);
}
return document;
Expand All @@ -200,7 +231,7 @@ public static string ToJson<TNominalType>(
JsonWriterSettings writerSettings = null,
IBsonSerializer<TNominalType> serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
BsonSerializationArgs args = default)
{
args.SetOrValidateNominalType(typeof(TNominalType), "<TNominalType>");
return ToJson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args);
Expand All @@ -226,7 +257,17 @@ public static string ToJson(
JsonWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
BsonSerializationArgs args = default)
=> ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args);

private static string ToJson(
this object obj,
Type nominalType,
IBsonSerializationDomain domain,
JsonWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action<BsonSerializationContext.Builder> configurator = null,
BsonSerializationArgs args = default)
{
if (nominalType == null)
{
Expand All @@ -236,7 +277,7 @@ public static string ToJson(

if (serializer == null)
{
serializer = BsonSerializer.LookupSerializer(nominalType);
serializer = domain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
Expand All @@ -248,7 +289,7 @@ public static string ToJson(
{
using (var bsonWriter = new JsonWriter(stringWriter, writerSettings ?? JsonWriterSettings.Defaults))
{
var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
var context = BsonSerializationContext.CreateRoot(bsonWriter, domain, configurator);
serializer.Serialize(context, args, obj);
}
return stringWriter.ToString();
Expand Down
39 changes: 39 additions & 0 deletions src/MongoDB.Bson/IBsonDefaults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using MongoDB.Bson.Serialization;

namespace MongoDB.Bson
{
internal interface IBsonDefaults
{
/// <summary>
///
/// </summary>
IBsonSerializer DynamicArraySerializer { get; set; }
/// <summary>
///
/// </summary>
IBsonSerializer DynamicDocumentSerializer { get; set; }
/// <summary>
///
/// </summary>
int MaxDocumentSize { get; set; }
/// <summary>
///
/// </summary>
int MaxSerializationDepth { get; set; }
}
}
6 changes: 3 additions & 3 deletions src/MongoDB.Bson/IO/BsonReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,13 +321,13 @@ public virtual IByteBuffer ReadRawBsonArray()
// overridden in BsonBinaryReader to read the raw bytes from the stream
// for all other streams, deserialize the array and reserialize it using a BsonBinaryWriter to get the raw bytes

var deserializationContext = BsonDeserializationContext.CreateRoot(this);
var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need a domain for RawBsonArray/RawBsonDocument?
Ideally BsonReader should read raw bson values, and seems that this is the case?
Does it work if passing a null domain?

Another idea to address all "default domain" questions: We can consider having some simplified version of BsonValueSerializer, for example BsonValueSerializationUtils that just works with IBsonReader.
cc @rstam

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I was not sure if we're dealing only with BsonValue, is this the case @rstam?

If so this is the perfect place to address the fact that in my opinion we need to have another kind of domain around.
A "standard domain", that contains all the default serializers, and that cannot be modified. This is used, for instance with GridFS or when serializing commands. In those cases the serialization should not be influenced by the kind of serializers that developers have registered. Imagine what would happen if a developer register a different IntSerializer that just adds 4 to all values.
This standard domain should be read-only and only be accessed internally, probably.

var array = BsonArraySerializer.Instance.Deserialize(deserializationContext);

using (var memoryStream = new MemoryStream())
using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults))
{
var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter);
var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain);
bsonWriter.WriteStartDocument();
var startPosition = memoryStream.Position + 3; // just past BsonType, "x" and null byte
bsonWriter.WriteName("x");
Expand All @@ -351,7 +351,7 @@ public virtual IByteBuffer ReadRawBsonDocument()
// overridden in BsonBinaryReader to read the raw bytes from the stream
// for all other streams, deserialize the document and use ToBson to get the raw bytes

var deserializationContext = BsonDeserializationContext.CreateRoot(this);
var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);
var bytes = document.ToBson();
return new ByteArrayBuffer(bytes, isReadOnly: true);
Expand Down
Loading