Skip to content

Commit 2d3e62f

Browse files
authored
CSHARP4040: Fix bug when using field with same element name as discriminator (#1684)
1 parent 66f3552 commit 2d3e62f

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

src/MongoDB.Bson/Serialization/BsonClassMap.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1323,10 +1323,25 @@ internal IDiscriminatorConvention GetDiscriminatorConvention()
13231323
var discriminatorConvention = _discriminatorConvention;
13241324
if (discriminatorConvention == null)
13251325
{
1326-
// it's possible but harmless for multiple threads to do the discriminator convention lookukp at the same time
1326+
// it's possible but harmless for multiple threads to do the discriminator convention lookup at the same time
13271327
discriminatorConvention = LookupDiscriminatorConvention();
13281328
_discriminatorConvention = discriminatorConvention;
1329+
1330+
if (discriminatorConvention != null)
1331+
{
1332+
var conflictingMemberMap = _allMemberMaps.FirstOrDefault(memberMap => memberMap.ElementName == discriminatorConvention.ElementName);
1333+
1334+
if (conflictingMemberMap != null)
1335+
{
1336+
var fieldOrProperty = conflictingMemberMap.MemberInfo is FieldInfo ? "field" : "property";
1337+
1338+
throw new BsonSerializationException(
1339+
$"The discriminator element name cannot be {discriminatorConvention.ElementName} " +
1340+
$"because it is already being used by the {fieldOrProperty} {conflictingMemberMap.MemberName} of type {_classType.FullName}");
1341+
}
1342+
}
13291343
}
1344+
13301345
return discriminatorConvention;
13311346

13321347
IDiscriminatorConvention LookupDiscriminatorConvention()

src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ public abstract class StandardDiscriminatorConvention : IDiscriminatorConvention
3939
/// <param name="elementName">The element name.</param>
4040
protected StandardDiscriminatorConvention(string elementName)
4141
{
42-
if (elementName == null)
42+
if (string.IsNullOrEmpty(elementName))
4343
{
44-
throw new ArgumentNullException("elementName");
44+
throw new ArgumentException("Discriminator element name name cannot be null or empty.", nameof(elementName));
4545
}
4646
if (elementName.IndexOf('\0') != -1)
4747
{
48-
throw new ArgumentException("Element names cannot contain nulls.", "elementName");
48+
throw new ArgumentException("Discriminator element name cannot contain nulls.", nameof(elementName));
4949
}
50+
5051
_elementName = elementName;
5152
}
5253

tests/MongoDB.Bson.Tests/Serialization/Conventions/StandardDiscriminatorConventionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void TestConstructorThrowsWhenElementNameContainsNulls()
3131
[Fact]
3232
public void TestConstructorThrowsWhenElementNameIsNull()
3333
{
34-
Assert.Throws<ArgumentNullException>(() => new ScalarDiscriminatorConvention(null));
34+
Assert.Throws<ArgumentException>(() => new ScalarDiscriminatorConvention(null));
3535
}
3636

3737
[Fact]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using FluentAssertions;
17+
using MongoDB.Bson;
18+
using MongoDB.Bson.Serialization.Attributes;
19+
using Xunit;
20+
21+
namespace MongoDB.Driver.Tests.Jira
22+
{
23+
public class CSharp4040Tests
24+
{
25+
private class BaseDocument
26+
{
27+
[BsonId] public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
28+
29+
[BsonElement("_t")]
30+
public string Field1 { get; set; }
31+
}
32+
33+
private class DerivedDocument : BaseDocument {}
34+
35+
[Fact]
36+
public void BsonClassMapSerializer_serialization_when_using_field_with_same_element_name_as_discriminator_should_throw()
37+
{
38+
var obj = new DerivedDocument { Field1 = "field1" };
39+
40+
var recordedException = Record.Exception(() => obj.ToJson(typeof(BaseDocument)));
41+
recordedException.Should().NotBeNull();
42+
recordedException.Should().BeOfType<BsonSerializationException>();
43+
recordedException.Message.Should().Be("The discriminator element name cannot be _t because it is already being used" +
44+
" by the property Field1 of type MongoDB.Driver.Tests.Jira.CSharp4040Tests+DerivedDocument");
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)