public void Apply(BsonClassMap classMap) { var readOnlyProperties = classMap .ClassType .GetTypeInfo() .GetProperties(_bindingFlags) .Where(p => IsReadOnlyProperty(classMap, p)) .ToList(); foreach (var constructor in classMap.ClassType.GetConstructors()) { // If we found a matching constructor then we map it and all the readonly properties var matchProperties = GetMatchingProperties(constructor, readOnlyProperties); if (matchProperties.Any()) { // Map constructor classMap.MapConstructor(constructor); // Map properties foreach (var p in matchProperties) { classMap.MapMember(p); } } } }
public void Apply(BsonClassMap classMap) { var constructors = classMap .ClassType .GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance) .Concat(classMap.ClassType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)); var shortestContructor = constructors .OrderBy(ctor => ctor.GetParameters().Length) .ThenBy(ctor => ctor.IsPublic) //Prioritize protected/private constructors .FirstOrDefault(); classMap.MapConstructor(shortestContructor); var publicProperties = classMap.ClassType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead); foreach (var publicProperty in publicProperties) { if (publicProperty.Name == "Id") { classMap.MapIdMember(publicProperty).SetIdGenerator(StringObjectIdGenerator.Instance); } } }
private void OptInMembersWithBsonCreatorMapModifierAttribute(BsonClassMap classMap) { // let other constructors opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var constructorInfo in classMap.ClassType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { #if NETCORE50 || NETSTANDARD1_5 || NETSTANDARD1_6 var hasAttribute = constructorInfo.CustomAttributes.Any(c => c.AttributeType is IBsonCreatorMapAttribute); #else var hasAttribute = constructorInfo.GetCustomAttributes(typeof(IBsonCreatorMapAttribute), false).Any(); #endif if (hasAttribute) { classMap.MapConstructor(constructorInfo); } } // let other static factory methods opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var methodInfo in classMap.ClassType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { #if NETCORE50 || NETSTANDARD1_5 || NETSTANDARD1_6 var hasAttribute = methodInfo.CustomAttributes.Any(c => c.AttributeType is IBsonCreatorMapAttribute); #else var hasAttribute = methodInfo.GetCustomAttributes(typeof(IBsonCreatorMapAttribute), false).Any(); #endif if (hasAttribute) { classMap.MapFactoryMethod(methodInfo); } } }
/// <inheritdoc /> public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.IsAbstract) { return; } if (typeInfo.GetConstructor(Type.EmptyTypes) != null) { return; } var properties = typeInfo.GetProperties(); if (properties.Any(p => p.CanWrite)) { return; // a type that has any writable properties is not immutable } var anyConstructorsWereMapped = false; foreach (var ctor in typeInfo.GetConstructors()) { var parameters = ctor.GetParameters(); if (parameters.Length != properties.Length) { continue; // only consider constructors that have sufficient parameters to initialize all properties } var matches = parameters .GroupJoin(properties, parameter => parameter.Name, property => property.Name, (parameter, props) => new { Parameter = parameter, Properties = props }, StringComparer.OrdinalIgnoreCase); if (matches.Any(m => m.Properties.Count() != 1)) { continue; } classMap.MapConstructor(ctor); anyConstructorsWereMapped = true; } if (anyConstructorsWereMapped) { // if any constructors were mapped by this convention then map all the properties also foreach (var property in properties) { classMap.MapMember(property); } } }
public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.IsAbstract) { return; } if (typeInfo.GetInterface("IImmutable") == null) { return; // only applies to classes that inherit from IImutable } var properties = typeInfo.GetProperties(); var anyConstructorsWereMapped = false; ConstructorInfo[] constructors = typeInfo.GetConstructors(); if (constructors.Length > 0) { var ctor = typeInfo.GetConstructors().OrderByDescending(x => x.GetParameters().Count()).First(); var parameters = ctor.GetParameters(); var matches = parameters .GroupJoin(properties, parameter => parameter.Name, property => property.Name, (parameter, props) => new { Parameter = parameter, Properties = props }, StringComparer.OrdinalIgnoreCase); if (matches.Any(m => m.Properties.Count() != 1)) { //continue; } classMap.MapConstructor(ctor); anyConstructorsWereMapped = true; } if (anyConstructorsWereMapped) { var classType = classMap.ClassType; foreach (var property in properties) { if (property.DeclaringType == classType) { classMap.MapMember(property); } } } }
public void Apply_should_set_arguments_when_constructor_parameter_names_match_a_field() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap<C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(long) }); var creatorMap = classMap.MapConstructor(constructorInfo); creatorMap.Arguments.Should().BeNull(); subject.Apply(creatorMap); creatorMap.Arguments.Cast<FieldInfo>().Select(p => p.Name).Should().Equal(new[] { "F" }); }
public void Apply_should_do_nothing_when_constructor_parameter_name_does_not_match_any_property_or_field() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap<C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(int) }); var creatorMap = classMap.MapConstructor(constructorInfo); creatorMap.Arguments.Should().BeNull(); subject.Apply(creatorMap); creatorMap.Arguments.Should().BeNull(); }
public void Apply_should_do_nothing_when_creator_map_already_has_arguments_configured() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap<C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(int) }); var creatorMap = classMap.MapConstructor(constructorInfo, "Y"); var originalArguments = creatorMap.Arguments; subject.Apply(creatorMap); creatorMap.Arguments.Should().BeSameAs(originalArguments); }
public void Apply_should_do_nothing_when_creator_map_already_has_arguments_configured() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap <C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(int) }); var creatorMap = classMap.MapConstructor(constructorInfo, "Y"); var originalArguments = creatorMap.Arguments; subject.Apply(creatorMap); creatorMap.Arguments.Should().BeSameAs(originalArguments); }
private IBsonSerializer BuildProjectedSerializer(ProjectionMapping mapping) { // We are building a serializer specifically for a projected type based // on serialization information collected from other serializers. // We cannot cache this in the serializer registry because the compiler reuses // the same anonymous type definition in different contexts as long as they // are structurally equatable. As such, it might be that two different queries // projecting the same shape might need to be deserialized differently. var classMapType = typeof(BsonClassMap <>).MakeGenericType(mapping.Expression.Type); BsonClassMap classMap = (BsonClassMap)Activator.CreateInstance(classMapType); foreach (var memberMapping in mapping.Members) { var serializationExpression = memberMapping.Expression as ISerializationExpression; if (serializationExpression == null) { var serializer = Build(memberMapping.Expression); var serializationInfo = new BsonSerializationInfo( memberMapping.Member.Name, serializer, TypeHelper.GetMemberType(memberMapping.Member)); serializationExpression = new SerializationExpression( memberMapping.Expression, serializationInfo); } var memberMap = classMap.MapMember(memberMapping.Member) .SetSerializer(serializationExpression.SerializationInfo.Serializer) .SetElementName(memberMapping.Member.Name); if (classMap.IdMemberMap == null && serializationExpression is IdExpression) { classMap.SetIdMember(memberMap); } } var mappedParameters = mapping.Members .Where(x => x.Parameter != null) .OrderBy(x => x.Parameter.Position) .Select(x => x.Member) .ToList(); if (mappedParameters.Count > 0) { classMap.MapConstructor(mapping.Constructor) .SetArguments(mappedParameters); } var serializerType = typeof(BsonClassMapSerializer <>).MakeGenericType(mapping.Expression.Type); return((IBsonSerializer)Activator.CreateInstance(serializerType, classMap.Freeze())); }
public void Apply_should_set_arguments_when_constructor_parameter_names_match_a_property() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap <C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(string) }); var creatorMap = classMap.MapConstructor(constructorInfo); creatorMap.Arguments.Should().BeNull(); subject.Apply(creatorMap); creatorMap.Arguments.Cast <PropertyInfo>().Select(p => p.Name).Should().Equal(new[] { "P" }); }
public void Apply_should_do_nothing_when_constructor_parameter_name_does_not_match_any_property_or_field() { var subject = new NamedParameterCreatorMapConvention(); var classMap = new BsonClassMap <C>(); var constructorInfo = typeof(C).GetTypeInfo().GetConstructor(new[] { typeof(int) }); var creatorMap = classMap.MapConstructor(constructorInfo); creatorMap.Arguments.Should().BeNull(); subject.Apply(creatorMap); creatorMap.Arguments.Should().BeNull(); }
public void Apply(BsonClassMap classMap) { var nonPublicCtors = classMap.ClassType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance); var longestCtor = nonPublicCtors.OrderByDescending(ctor => ctor.GetParameters().Length).FirstOrDefault(); classMap.MapConstructor(longestCtor); var publicProperties = classMap.ClassType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead); foreach (var publicProperty in publicProperties) { classMap.MapMember(publicProperty); } }
private IBsonSerializer BuildSerializerForAnonymousType(NewExpression node) { // We are building a serializer specifically for an anonymous type based // on serialization information collected from other serializers. // We cannot cache this because the compiler reuses the same anonymous type // definition in different contexts as long as they are structurally equatable. // As such, it might be that two different queries projecting the same shape // might need to be deserialized differently. var classMapType = typeof(BsonClassMap <>).MakeGenericType(node.Type); BsonClassMap classMap = (BsonClassMap)Activator.CreateInstance(classMapType); var properties = node.Type.GetProperties(); var parameterToPropertyMap = from parameter in node.Constructor.GetParameters() join property in properties on parameter.Name equals property.Name select new { Parameter = parameter, Property = property }; foreach (var parameterToProperty in parameterToPropertyMap) { var argument = node.Arguments[parameterToProperty.Parameter.Position]; var serializationExpression = argument as ISerializationExpression; if (serializationExpression == null) { var serializer = Build(argument); var serializationInfo = new BsonSerializationInfo(parameterToProperty.Property.Name, serializer, parameterToProperty.Property.PropertyType); serializationExpression = new SerializationExpression( node.Arguments[parameterToProperty.Parameter.Position], serializationInfo); } var memberMap = classMap.MapMember(parameterToProperty.Property) .SetSerializer(serializationExpression.SerializationInfo.Serializer) .SetElementName(parameterToProperty.Property.Name); if (classMap.IdMemberMap == null && serializationExpression is IdExpression) { classMap.SetIdMember(memberMap); } //TODO: Need to set default value as well... } // Anonymous types are immutable and have all their values passed in via a ctor. classMap.MapConstructor(node.Constructor, properties.Select(x => x.Name).ToArray()); classMap.Freeze(); var serializerType = typeof(BsonClassMapSerializer <>).MakeGenericType(node.Type); return((IBsonSerializer)Activator.CreateInstance(serializerType, classMap)); }
private void OptInMembersWithBsonCreatorMapModifierAttribute(BsonClassMap classMap) { // let other constructors opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var constructorInfo in classMap.ClassType.GetTypeInfo().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { var hasAttribute = constructorInfo.GetCustomAttributes(inherit: false).OfType <IBsonCreatorMapAttribute>().Any(); if (hasAttribute) { classMap.MapConstructor(constructorInfo); } } // let other static factory methods opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var methodInfo in classMap.ClassType.GetTypeInfo().GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { var hasAttribute = methodInfo.GetCustomAttributes(inherit: false).OfType <IBsonCreatorMapAttribute>().Any(); if (hasAttribute) { classMap.MapFactoryMethod(methodInfo); } } }
public void Apply(BsonClassMap classMap) { var properties = classMap.ClassType .GetTypeInfo() .GetProperties(_bindingFlags) .Where(p => p.PropertyType != typeof(Type)) .ToList(); var mappingProperties = properties .Where(p => IsReadOnlyProperty(classMap, p) || IsInitOnlyProperty(p)) .ToList(); foreach (PropertyInfo property in mappingProperties) { BsonMemberMap member = classMap.MapMember(property); if (IsNullableProperty(property)) { member.SetDefaultValue((object?)null); } } if (!classMap.ClassType.IsAbstract) { foreach (ConstructorInfo constructor in classMap.ClassType.GetConstructors( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { List <PropertyInfo> matchProperties = GetMatchingProperties(constructor, properties); if (matchProperties.Any()) { BsonCreatorMap creatorMap = classMap.MapConstructor(constructor); creatorMap.SetArguments(matchProperties); } } } }
/// <inheritdoc /> public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.IsAbstract) { return; } if (typeInfo.GetConstructor(Type.EmptyTypes) != null) { return; } foreach (var ctor in typeInfo.GetConstructors()) { var parameters = ctor.GetParameters(); var properties = typeInfo.GetProperties(); if (parameters.Length != properties.Length) { continue; } var matches = parameters .GroupJoin(properties, parameter => parameter.Name, property => property.Name, (parameter, props) => new { parameter, properties = props }, StringComparer.OrdinalIgnoreCase); if (matches.Any(m => m.properties.Count() != 1 || m.properties.ElementAt(0).CanWrite)) { continue; } classMap.MapConstructor(ctor); } }
public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.GetConstructor(Type.EmptyTypes) != null) { return; } var propertyBindingFlags = BindingFlags.Public | BindingFlags.Instance; var properties = typeInfo.GetProperties(propertyBindingFlags).Where(x => x.CanWrite); var constructorBindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; var zeroParameterCtor = typeInfo.GetConstructors(constructorBindingFlags).FirstOrDefault(x => x.GetParameters().Length == 0); if (typeInfo.IsAbstract is false && zeroParameterCtor != null) { (classMap.CreatorMaps as List <BsonCreatorMap>)?.Clear(); classMap.MapConstructor(zeroParameterCtor); } foreach (var property in properties) { if (property.DeclaringType != classMap.ClassType) { continue; } var memberMap = classMap.MapMember(property); if (classMap.IsAnonymous) { var defaultValue = memberMap.DefaultValue; memberMap.SetDefaultValue(defaultValue); } } }
public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.IsAbstract) { return; } if (typeInfo.GetInterface("IImmutable") == null) { return; // only applies to classes that inherit from IImutable } var properties = typeInfo.GetProperties(); var anyConstructorsWereMapped = false; ConstructorInfo[] constructors = typeInfo.GetConstructors(); if (constructors.Length > 0) { var ctor = typeInfo.GetConstructors().OrderByDescending(x => x.GetParameters().Count()).First(); var parameters = ctor.GetParameters(); var matches = parameters .GroupJoin(properties, parameter => parameter.Name, property => property.Name, (parameter, props) => new { Parameter = parameter, Properties = props }, StringComparer.OrdinalIgnoreCase); if (matches.Any(m => m.Properties.Count() != 1)) { //continue; } classMap.MapConstructor(ctor); anyConstructorsWereMapped = true; } if (anyConstructorsWereMapped) { var classType = classMap.ClassType; foreach (var property in properties) { if (property.DeclaringType == classType && !IsOverridden(property)) { classMap.MapMember(property); } else if (!property.CanWrite && classType.BaseType != null && classType.BaseType.IsAbstract) { //Forcing immutable properties from base class to be added via reflection. //This is due to BsonClassMap refusing to add members from base class to the class map which is needed //for IImmutable members withg an abstract immutable base class. var memberMap = classMap.DeclaredMemberMaps.ToList().Find(m => m.MemberInfo == property); if (memberMap == null) { memberMap = new BsonMemberMap(classMap, property); FieldInfo info = typeof(BsonClassMap).GetField("_declaredMemberMaps", BindingFlags.NonPublic | BindingFlags.Instance); var declaredMemberMaps = info.GetValue(classMap) as List <BsonMemberMap>; declaredMemberMaps.Add(memberMap); } } } } }
/// <inheritdoc /> public void Apply(BsonClassMap classMap) { var typeInfo = classMap.ClassType.GetTypeInfo(); if (typeInfo.GetConstructor(Type.EmptyTypes) != null) { return; } var propertyBindingFlags = BindingFlags.Public | BindingFlags.Instance; var properties = typeInfo.GetProperties(propertyBindingFlags); if (properties.Any(CanWrite)) { return; // a type that has any writable properties is not immutable } var anyConstructorsWereFound = false; var constructorBindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; foreach (var ctor in typeInfo.GetConstructors(constructorBindingFlags)) { if (ctor.IsPrivate) { continue; // do not consider private constructors } var parameters = ctor.GetParameters(); if (parameters.Length != properties.Length) { continue; // only consider constructors that have sufficient parameters to initialize all properties } var matches = parameters .GroupJoin(properties, parameter => parameter.Name, property => property.Name, (parameter, props) => new { Parameter = parameter, Properties = props }, StringComparer.OrdinalIgnoreCase); if (matches.Any(m => m.Properties.Count() != 1)) { continue; } if (ctor.IsPublic && !typeInfo.IsAbstract) { // we need to save constructorInfo only for public constructors in non abstract classes classMap.MapConstructor(ctor); } anyConstructorsWereFound = true; } if (anyConstructorsWereFound) { // if any constructors were found by this convention // then map all the properties from the ClassType inheritance level also foreach (var property in properties) { if (property.DeclaringType != classMap.ClassType) { continue; } var memberMap = classMap.MapMember(property); if (classMap.IsAnonymous) { var defaultValue = memberMap.DefaultValue; memberMap.SetDefaultValue(defaultValue); } } } }
private void OptInMembersWithBsonCreatorMapModifierAttribute(BsonClassMap classMap) { // let other constructors opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var constructorInfo in classMap.ClassType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { var hasAttribute = constructorInfo.GetCustomAttributes(typeof(IBsonCreatorMapAttribute), false).Any(); if (hasAttribute) { classMap.MapConstructor(constructorInfo); } } // let other static factory methods opt-in if they have any IBsonCreatorMapAttribute attributes foreach (var methodInfo in classMap.ClassType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { var hasAttribute = methodInfo.GetCustomAttributes(typeof(IBsonCreatorMapAttribute), false).Any(); if (hasAttribute) { classMap.MapFactoryMethod(methodInfo); } } }