Skip to content

Commit 3b27b43

Browse files
committed
Moved class map to another file
1 parent d6d9ddc commit 3b27b43

File tree

2 files changed

+257
-284
lines changed

2 files changed

+257
-284
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
namespace MongoDB.Bson.Serialization;
7+
8+
internal class BsonClassMapDomain : IBsonClassMapDomain
9+
{
10+
// private fields
11+
private readonly Dictionary<Type, BsonClassMap> _classMaps = new();
12+
13+
/// <summary>
14+
/// Gets all registered class maps.
15+
/// </summary>
16+
/// <returns>All registered class maps.</returns>
17+
public IEnumerable<BsonClassMap> GetRegisteredClassMaps()
18+
{
19+
BsonSerializer.ConfigLock.EnterReadLock(); //TODO It would make sense to look at this after the PR by Robert is merged
20+
try
21+
{
22+
return _classMaps.Values.ToList(); // return a copy for thread safety
23+
}
24+
finally
25+
{
26+
BsonSerializer.ConfigLock.ExitReadLock();
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Checks whether a class map is registered for a type.
32+
/// </summary>
33+
/// <param name="type">The type to check.</param>
34+
/// <returns>True if there is a class map registered for the type.</returns>
35+
public bool IsClassMapRegistered(Type type)
36+
{
37+
if (type == null)
38+
{
39+
throw new ArgumentNullException("type");
40+
}
41+
42+
BsonSerializer.ConfigLock.EnterReadLock();
43+
try
44+
{
45+
return _classMaps.ContainsKey(type);
46+
}
47+
finally
48+
{
49+
BsonSerializer.ConfigLock.ExitReadLock();
50+
}
51+
}
52+
53+
/// <summary>
54+
/// Looks up a class map (will AutoMap the class if no class map is registered).
55+
/// </summary>
56+
/// <param name="classType">The class type.</param>
57+
/// <returns>The class map.</returns>
58+
public BsonClassMap LookupClassMap(Type classType)
59+
{
60+
if (classType == null)
61+
{
62+
throw new ArgumentNullException("classType");
63+
}
64+
65+
BsonSerializer.ConfigLock.EnterReadLock();
66+
try
67+
{
68+
if (_classMaps.TryGetValue(classType, out var classMap))
69+
{
70+
if (classMap.IsFrozen)
71+
{
72+
return classMap;
73+
}
74+
}
75+
}
76+
finally
77+
{
78+
BsonSerializer.ConfigLock.ExitReadLock();
79+
}
80+
81+
// automatically create a new classMap for classType and register it (unless another thread does first)
82+
// do the work of speculatively creating a new class map outside of holding any lock
83+
var classMapDefinition = typeof(BsonClassMap<>);
84+
var classMapType = classMapDefinition.MakeGenericType(classType);
85+
var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType);
86+
newClassMap.AutoMap();
87+
88+
BsonSerializer.ConfigLock.EnterWriteLock();
89+
try
90+
{
91+
if (!_classMaps.TryGetValue(classType, out var classMap))
92+
{
93+
RegisterClassMap(newClassMap);
94+
classMap = newClassMap;
95+
}
96+
97+
return classMap.Freeze();
98+
}
99+
finally
100+
{
101+
BsonSerializer.ConfigLock.ExitWriteLock();
102+
}
103+
}
104+
105+
/// <summary>
106+
/// Creates and registers a class map.
107+
/// </summary>
108+
/// <typeparam name="TClass">The class.</typeparam>
109+
/// <returns>The class map.</returns>
110+
public BsonClassMap<TClass> RegisterClassMap<TClass>()
111+
{
112+
return RegisterClassMap<TClass>(cm => { cm.AutoMap(); });
113+
}
114+
115+
/// <summary>
116+
/// Creates and registers a class map.
117+
/// </summary>
118+
/// <typeparam name="TClass">The class.</typeparam>
119+
/// <param name="classMapInitializer">The class map initializer.</param>
120+
/// <returns>The class map.</returns>
121+
public BsonClassMap<TClass> RegisterClassMap<TClass>(Action<BsonClassMap<TClass>> classMapInitializer)
122+
{
123+
var classMap = new BsonClassMap<TClass>(classMapInitializer);
124+
RegisterClassMap(classMap);
125+
return classMap;
126+
}
127+
128+
/// <summary>
129+
/// Registers a class map.
130+
/// </summary>
131+
/// <param name="classMap">The class map.</param>
132+
public void RegisterClassMap(BsonClassMap classMap)
133+
{
134+
if (classMap == null)
135+
{
136+
throw new ArgumentNullException("classMap");
137+
}
138+
139+
BsonSerializer.ConfigLock.EnterWriteLock();
140+
try
141+
{
142+
// note: class maps can NOT be replaced (because derived classes refer to existing instance)
143+
_classMaps.Add(classMap.ClassType, classMap);
144+
BsonSerializer.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
145+
}
146+
finally
147+
{
148+
BsonSerializer.ConfigLock.ExitWriteLock();
149+
}
150+
}
151+
152+
/// <summary>
153+
/// Registers a class map if it is not already registered.
154+
/// </summary>
155+
/// <typeparam name="TClass">The class.</typeparam>
156+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
157+
public bool TryRegisterClassMap<TClass>()
158+
{
159+
return TryRegisterClassMap(ClassMapFactory);
160+
161+
static BsonClassMap<TClass> ClassMapFactory()
162+
{
163+
var classMap = new BsonClassMap<TClass>();
164+
classMap.AutoMap();
165+
return classMap;
166+
}
167+
}
168+
169+
/// <summary>
170+
/// Registers a class map if it is not already registered.
171+
/// </summary>
172+
/// <typeparam name="TClass">The class.</typeparam>
173+
/// <param name="classMap">The class map.</param>
174+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
175+
public bool TryRegisterClassMap<TClass>(BsonClassMap<TClass> classMap)
176+
{
177+
if (classMap == null)
178+
{
179+
throw new ArgumentNullException(nameof(classMap));
180+
}
181+
182+
return TryRegisterClassMap(ClassMapFactory);
183+
184+
BsonClassMap<TClass> ClassMapFactory()
185+
{
186+
return classMap;
187+
}
188+
}
189+
190+
/// <summary>
191+
/// Registers a class map if it is not already registered.
192+
/// </summary>
193+
/// <typeparam name="TClass">The class.</typeparam>
194+
/// <param name="classMapInitializer">The class map initializer (only called if the class map is not already registered).</param>
195+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
196+
public bool TryRegisterClassMap<TClass>(Action<BsonClassMap<TClass>> classMapInitializer)
197+
{
198+
if (classMapInitializer == null)
199+
{
200+
throw new ArgumentNullException(nameof(classMapInitializer));
201+
}
202+
203+
return TryRegisterClassMap(ClassMapFactory);
204+
205+
BsonClassMap<TClass> ClassMapFactory()
206+
{
207+
return new BsonClassMap<TClass>(classMapInitializer);
208+
}
209+
}
210+
211+
/// <summary>
212+
/// Registers a class map if it is not already registered.
213+
/// </summary>
214+
/// <typeparam name="TClass">The class.</typeparam>
215+
/// <param name="classMapFactory">The class map factory (only called if the class map is not already registered).</param>
216+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
217+
public bool TryRegisterClassMap<TClass>(Func<BsonClassMap<TClass>> classMapFactory)
218+
{
219+
if (classMapFactory == null)
220+
{
221+
throw new ArgumentNullException(nameof(classMapFactory));
222+
}
223+
224+
BsonSerializer.ConfigLock.EnterReadLock();
225+
try
226+
{
227+
if (_classMaps.ContainsKey(typeof(TClass)))
228+
{
229+
return false;
230+
}
231+
}
232+
finally
233+
{
234+
BsonSerializer.ConfigLock.ExitReadLock();
235+
}
236+
237+
BsonSerializer.ConfigLock.EnterWriteLock();
238+
try
239+
{
240+
if (_classMaps.ContainsKey(typeof(TClass)))
241+
{
242+
return false;
243+
}
244+
else
245+
{
246+
// create a classMap for TClass and register it
247+
var classMap = classMapFactory();
248+
RegisterClassMap(classMap);
249+
return true;
250+
}
251+
}
252+
finally
253+
{
254+
BsonSerializer.ConfigLock.ExitWriteLock();
255+
}
256+
}
257+
}

0 commit comments

Comments
 (0)