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 System ;
17+ using System . Collections . Generic ;
18+ using System . Linq ;
19+ using System . Reflection ;
20+ using MongoDB . Bson . Serialization . Serializers ;
21+
22+ namespace MongoDB . Bson . Serialization . Conventions
23+ {
24+ /// <summary>
25+ /// A convention that allows to set the types that can be safely serialized and deserialized with the <see cref="ObjectSerializer"/>.
26+ /// </summary>
27+ public sealed class ObjectSerializerAllowedTypesConvention : ConventionBase , IMemberMapConvention
28+ {
29+ // static properties
30+
31+ /// <summary>
32+ /// A predefined <see cref="ObjectSerializerAllowedTypesConvention"/> where all types are allowed for both serialization and deserialization.
33+ /// </summary>
34+ public static ObjectSerializerAllowedTypesConvention AllowAllTypes { get ; } = new ( ObjectSerializer . AllAllowedTypes ) ;
35+
36+ /// <summary>
37+ /// A predefined <see cref="ObjectSerializerAllowedTypesConvention"/> where no types are allowed for both serialization and deserialization.
38+ /// </summary>
39+ public static ObjectSerializerAllowedTypesConvention AllowNoTypes { get ; } =
40+ new ( ObjectSerializer . NoAllowedTypes ) { AllowDefaultFrameworkTypes = false } ;
41+
42+ /// <summary>
43+ /// A predefined <see cref="ObjectSerializerAllowedTypesConvention"/> where only default framework types are allowed for both serialization and deserialization.
44+ /// </summary>
45+ public static ObjectSerializerAllowedTypesConvention AllowOnlyDefaultFrameworkTypes { get ; } = new ( ) ;
46+
47+ //static methods
48+
49+ /// <summary>
50+ /// Builds a predefined <see cref="ObjectSerializerAllowedTypesConvention"/> where all calling assembly types and default framework types are allowed for both serialization and deserialization.
51+ /// </summary>
52+ public static ObjectSerializerAllowedTypesConvention GetAllowAllCallingAssemblyAndDefaultFrameworkTypesConvention ( ) => new ( Assembly . GetCallingAssembly ( ) ) ;
53+
54+ // private fields
55+ private readonly Func < Type , bool > _allowedDeserializationTypes ;
56+ private readonly Func < Type , bool > _allowedSerializationTypes ;
57+ private readonly bool _allowDefaultFrameworkTypes = true ;
58+ private readonly Lazy < Func < Type , bool > > _effectiveAllowedDeserializationTypes ;
59+ private readonly Lazy < Func < Type , bool > > _effectiveAllowedSerializationTypes ;
60+
61+ /// <summary>
62+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
63+ /// </summary>
64+ /// <param name="allowedTypes">A delegate that determines what types are allowed to be serialized and deserialized.</param>
65+ public ObjectSerializerAllowedTypesConvention ( Func < Type , bool > allowedTypes )
66+ : this ( allowedTypes , allowedTypes )
67+ {
68+ }
69+
70+ /// <summary>
71+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
72+ /// </summary>
73+ /// <param name="allowedDeserializationTypes">A delegate that determines what types are allowed to be deserialized.</param>
74+ /// <param name="allowedSerializationTypes">A delegate that determines what types are allowed to be serialized.</param>
75+ public ObjectSerializerAllowedTypesConvention ( Func < Type , bool > allowedDeserializationTypes , Func < Type , bool > allowedSerializationTypes )
76+ : this ( )
77+ {
78+ _allowedDeserializationTypes = allowedDeserializationTypes ;
79+ _allowedSerializationTypes = allowedSerializationTypes ;
80+ }
81+
82+ /// <summary>
83+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
84+ /// </summary>
85+ /// <param name="allowedTypes">A collection of the allowed types for both serialization and deserialization.</param>
86+ public ObjectSerializerAllowedTypesConvention ( IEnumerable < Type > allowedTypes )
87+ : this ( )
88+ {
89+ var allowedTypesArray = allowedTypes . ToArray ( ) ;
90+
91+ _allowedDeserializationTypes = allowedTypesArray . Contains ;
92+ _allowedSerializationTypes = allowedTypesArray . Contains ;
93+ }
94+
95+ /// <summary>
96+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
97+ /// </summary>
98+ /// <param name="allowedDeserializationTypes">A collection of the allowed types for deserialization.</param>
99+ /// <param name="allowedSerializationTypes">A collection of the allowed types for serialization.</param>
100+ public ObjectSerializerAllowedTypesConvention ( IEnumerable < Type > allowedDeserializationTypes , IEnumerable < Type > allowedSerializationTypes )
101+ : this ( )
102+ {
103+ var allowedDeserializationTypesArray = allowedDeserializationTypes . ToArray ( ) ;
104+ var allowedSerializationTypesArray = allowedSerializationTypes . ToArray ( ) ;
105+
106+ _allowedDeserializationTypes = allowedDeserializationTypesArray . Contains ;
107+ _allowedSerializationTypes = allowedSerializationTypesArray . Contains ;
108+ }
109+
110+ /// <summary>
111+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
112+ /// </summary>
113+ /// <param name="allowedAssemblies">A collection of allowed assemblies whose types can be serialized and deserialized.</param>
114+ public ObjectSerializerAllowedTypesConvention ( params Assembly [ ] allowedAssemblies )
115+ : this ( )
116+ {
117+ _allowedDeserializationTypes = _allowedSerializationTypes = t => allowedAssemblies . Contains ( t . Assembly ) ;
118+ }
119+
120+ /// <summary>
121+ /// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class.
122+ /// </summary>
123+ public ObjectSerializerAllowedTypesConvention ( )
124+ {
125+ _effectiveAllowedDeserializationTypes = new Lazy < Func < Type , bool > > ( ( ) => CreateEffectiveAllowedTypes ( _allowedDeserializationTypes ) ) ;
126+ _effectiveAllowedSerializationTypes = new Lazy < Func < Type , bool > > ( ( ) => CreateEffectiveAllowedTypes ( _allowedSerializationTypes ) ) ;
127+
128+ Func < Type , bool > CreateEffectiveAllowedTypes ( Func < Type , bool > allowedTypes )
129+ {
130+ return ( allowedTypes , _allowDefaultFrameworkTypes ) switch
131+ {
132+ ( null , false ) => ObjectSerializer . NoAllowedTypes ,
133+ ( null , true ) => ObjectSerializer . DefaultAllowedTypes ,
134+ ( not null , false ) => allowedTypes ,
135+ ( not null , true ) => t => allowedTypes ( t ) || ObjectSerializer . DefaultAllowedTypes ( t )
136+ } ;
137+ }
138+ }
139+
140+ /// <summary>
141+ /// Indicates whether default framework types are included for serialization and deserialization. Defaults to true.
142+ /// </summary>
143+ public bool AllowDefaultFrameworkTypes
144+ {
145+ get => _allowDefaultFrameworkTypes ;
146+ init => _allowDefaultFrameworkTypes = value ;
147+ }
148+
149+ /// <summary>
150+ /// Applies a modification to the member map.
151+ /// </summary>
152+ /// <param name="memberMap">The member map.</param>
153+ public void Apply ( BsonMemberMap memberMap )
154+ {
155+ var serializer = memberMap . GetSerializer ( ) ;
156+
157+ var reconfiguredSerializer = Reconfigure ( serializer ) ;
158+ if ( reconfiguredSerializer is not null )
159+ {
160+ memberMap . SetSerializer ( reconfiguredSerializer ) ;
161+ }
162+ }
163+
164+ private IBsonSerializer Reconfigure ( IBsonSerializer serializer )
165+ {
166+ if ( serializer is IChildSerializerConfigurable childSerializerConfigurable )
167+ {
168+ var childSerializer = childSerializerConfigurable . ChildSerializer ;
169+ var reconfiguredChildSerializer = Reconfigure ( childSerializer ) ;
170+ return reconfiguredChildSerializer is null ? null : childSerializerConfigurable . WithChildSerializer ( reconfiguredChildSerializer ) ;
171+ }
172+
173+ if ( serializer . ValueType == typeof ( object ) && serializer is ObjectSerializer objectSerializer )
174+ {
175+ return objectSerializer . WithAllowedTypes ( _effectiveAllowedDeserializationTypes . Value , _effectiveAllowedSerializationTypes . Value ) ;
176+ }
177+
178+ return null ;
179+ }
180+ }
181+ }
0 commit comments