diff --git a/FluentProtobufNet.Tests/DevelopmentTests.cs b/FluentProtobufNet.Tests/DevelopmentTests.cs index d7d41ab..fc0dab9 100644 --- a/FluentProtobufNet.Tests/DevelopmentTests.cs +++ b/FluentProtobufNet.Tests/DevelopmentTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using FluentProtobufNet.Mapping; using NUnit.Framework; using System.Linq; using ProtoBuf.Meta; @@ -8,24 +8,32 @@ namespace FluentProtobufNet.Tests [TestFixture] public class DevelopmentTests { - [Test] - public Configuration CanBuildConfiguration() + private Configuration _config; + + [SetUp] + public void Setup() { - return Fluently.Configure() - .Mappings(m => + _config = Fluently.Configure() + .Mappings(m => m.FluentMappings.AddFromAssemblyOf()) .BuildConfiguration(); } [Test] - public void CorrectlyMapsSingleLevelSubclasses() + public void CanBuildConfiguration() { - var config = CanBuildConfiguration(); + Assert.IsNotNull(_config.RuntimeTypeModel); + Assert.Greater(_config.RuntimeTypeModel.GetTypes().Cast().Count(), 0); + } - var types = config.RuntimeTypeModel.GetTypes().Cast(); + [Test] + public void CorrectlyMapsSingleLevelSubclasses() + { + var types = _config.RuntimeTypeModel.GetTypes().Cast(); var category = types.SingleOrDefault(t => t.Type == typeof (Category)); + Assert.IsNotNull(category); Assert.IsTrue(category.HasSubtypes); Assert.IsTrue(category.GetSubtypes()[0].DerivedType.Type == typeof(CategoryWithDescription)); } @@ -33,12 +41,11 @@ public void CorrectlyMapsSingleLevelSubclasses() [Test] public void CorrectlyMapsUpToThirdLevelSubclass() { - var config = CanBuildConfiguration(); - - var types = config.RuntimeTypeModel.GetTypes().Cast(); + var types = _config.RuntimeTypeModel.GetTypes().Cast(); var categoryWithDescription = types.SingleOrDefault(t => t.Type == typeof(CategoryWithDescription)); + Assert.IsNotNull(categoryWithDescription); Assert.IsTrue(categoryWithDescription.HasSubtypes); Assert.IsTrue(categoryWithDescription.GetSubtypes()[0].DerivedType.Type == typeof(CategoryThirdLevel)); } diff --git a/FluentProtobufNet/AssemblyTypeSource.cs b/FluentProtobufNet/AssemblyTypeSource.cs index 03f9ee4..9c71ff7 100644 --- a/FluentProtobufNet/AssemblyTypeSource.cs +++ b/FluentProtobufNet/AssemblyTypeSource.cs @@ -7,20 +7,20 @@ namespace FluentProtobufNet { public class AssemblyTypeSource : ITypeSource { - readonly Assembly source; + readonly Assembly _source; public AssemblyTypeSource(Assembly source) { if (source == null) throw new ArgumentNullException("source"); - this.source = source; + _source = source; } #region ITypeSource Members public IEnumerable GetTypes() { - return source.GetTypes().OrderBy(x => x.FullName); + return _source.GetTypes().OrderBy(x => x.FullName); } public void LogSource(IDiagnosticLogger logger) @@ -32,14 +32,14 @@ public void LogSource(IDiagnosticLogger logger) public string GetIdentifier() { - return source.GetName().FullName; + return _source.GetName().FullName; } #endregion public override int GetHashCode() { - return source.GetHashCode(); + return _source.GetHashCode(); } } @@ -49,16 +49,4 @@ public interface ITypeSource //void LogSource(IDiagnosticLogger logger); string GetIdentifier(); } - - public interface IDiagnosticLogger - { - void Flush(); - void FluentMappingDiscovered(Type type); - void ConventionDiscovered(Type type); - void LoadedFluentMappingsFromSource(ITypeSource source); - void LoadedConventionsFromSource(ITypeSource source); - void AutomappingSkippedType(Type type, string reason); - void AutomappingCandidateTypes(IEnumerable types); - void BeginAutomappingType(Type type); - } } \ No newline at end of file diff --git a/FluentProtobufNet/Exceptions/FieldIdAlreadyUsedException.cs b/FluentProtobufNet/Exceptions/FieldIdAlreadyUsedException.cs new file mode 100644 index 0000000..a4f61b5 --- /dev/null +++ b/FluentProtobufNet/Exceptions/FieldIdAlreadyUsedException.cs @@ -0,0 +1,12 @@ +using System; +using ProtoBuf.Meta; + +namespace FluentProtobufNet.Exceptions +{ + public class FieldIdAlreadyUsedException : Exception + { + public FieldIdAlreadyUsedException(int fieldId, MetaType usedBy): base("The field ID " + fieldId + " has already been used by " + usedBy.Name) + { + } + } +} \ No newline at end of file diff --git a/FluentProtobufNet/Exceptions/InstantiationException.cs b/FluentProtobufNet/Exceptions/InstantiationException.cs new file mode 100644 index 0000000..218d89f --- /dev/null +++ b/FluentProtobufNet/Exceptions/InstantiationException.cs @@ -0,0 +1,18 @@ +using System; + +namespace FluentProtobufNet +{ + public class InstantiationException : Exception + { + public string Message { get; set; } + public Exception Exception { get; set; } + public Type Type { get; set; } + + public InstantiationException(string message, Exception exception, Type type) + { + Message = message; + Exception = exception; + Type = type; + } + } +} \ No newline at end of file diff --git a/FluentProtobufNet/Exceptions/MissingConstructorException.cs b/FluentProtobufNet/Exceptions/MissingConstructorException.cs new file mode 100644 index 0000000..a3d1be0 --- /dev/null +++ b/FluentProtobufNet/Exceptions/MissingConstructorException.cs @@ -0,0 +1,14 @@ +using System; + +namespace FluentProtobufNet.Exceptions +{ + public class MissingConstructorException : Exception + { + public Type Type { get; set; } + + public MissingConstructorException(Type type) + { + Type = type; + } + } +} \ No newline at end of file diff --git a/FluentProtobufNet/FluentConfiguration.cs b/FluentProtobufNet/FluentConfiguration.cs index c9d26e5..1456489 100644 --- a/FluentProtobufNet/FluentConfiguration.cs +++ b/FluentProtobufNet/FluentConfiguration.cs @@ -6,9 +6,8 @@ namespace FluentProtobufNet public class FluentConfiguration { private readonly Configuration _cfg; - private IDiagnosticLogger _logger; - readonly List> mappingsBuilders = new List>(); - private bool _mappingsSet; + private readonly IDiagnosticLogger _logger; + readonly List> _mappingsBuilders = new List>(); internal FluentConfiguration() : this(new Configuration()) @@ -22,8 +21,7 @@ public FluentConfiguration(Configuration cfg) public FluentConfiguration Mappings(Action mappings) { - mappingsBuilders.Add(mappings); - _mappingsSet = true; + _mappingsBuilders.Add(mappings); return this; } @@ -32,7 +30,7 @@ public Configuration BuildConfiguration() { var mappingCfg = new MappingConfiguration(_logger); - foreach (var builder in mappingsBuilders) + foreach (var builder in _mappingsBuilders) builder(mappingCfg); mappingCfg.Apply(Configuration); diff --git a/FluentProtobufNet/FluentProtobufNet.csproj b/FluentProtobufNet/FluentProtobufNet.csproj index 008ad5d..749d8b7 100644 --- a/FluentProtobufNet/FluentProtobufNet.csproj +++ b/FluentProtobufNet/FluentProtobufNet.csproj @@ -43,22 +43,26 @@ - + + + + + - + - - + - + + diff --git a/FluentProtobufNet/Helpers/LinqExtensions.cs b/FluentProtobufNet/Helpers/Extensions.cs similarity index 95% rename from FluentProtobufNet/Helpers/LinqExtensions.cs rename to FluentProtobufNet/Helpers/Extensions.cs index 588783b..412bce0 100644 --- a/FluentProtobufNet/Helpers/LinqExtensions.cs +++ b/FluentProtobufNet/Helpers/Extensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using FluentProtobufNet.Exceptions; namespace FluentProtobufNet.Helpers { diff --git a/FluentProtobufNet/Helpers/ReflectHelper.cs b/FluentProtobufNet/Helpers/ReflectHelper.cs new file mode 100644 index 0000000..85a9f1b --- /dev/null +++ b/FluentProtobufNet/Helpers/ReflectHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.Reflection; + +namespace FluentProtobufNet.Helpers +{ + public class ReflectHelper + { + public const BindingFlags AnyVisibilityInstance = BindingFlags.Instance | BindingFlags.Public | + BindingFlags.NonPublic; + private static readonly Type[] NoClasses = Type.EmptyTypes; + + public static ConstructorInfo GetDefaultConstructor(Type type) + { + if (IsAbstractClass(type)) + return null; + + try + { + ConstructorInfo constructor = + type.GetConstructor(AnyVisibilityInstance, null, CallingConventions.HasThis, NoClasses, null); + return constructor; + } + catch (Exception e) + { + throw new InstantiationException("A default (no-arg) constructor could not be found for: ", e, type); + } + } + + public static bool IsAbstractClass(System.Type type) + { + return (type.IsAbstract || type.IsInterface); + } + } +} \ No newline at end of file diff --git a/FluentProtobufNet/IDiagnosticLogger.cs b/FluentProtobufNet/IDiagnosticLogger.cs new file mode 100644 index 0000000..6a6ff0d --- /dev/null +++ b/FluentProtobufNet/IDiagnosticLogger.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace FluentProtobufNet +{ + public interface IDiagnosticLogger + { + void Flush(); + void FluentMappingDiscovered(Type type); + void ConventionDiscovered(Type type); + void LoadedFluentMappingsFromSource(ITypeSource source); + void LoadedConventionsFromSource(ITypeSource source); + void AutomappingSkippedType(Type type, string reason); + void AutomappingCandidateTypes(IEnumerable types); + void BeginAutomappingType(Type type); + } +} \ No newline at end of file diff --git a/FluentProtobufNet/ClassMap.cs b/FluentProtobufNet/Mapping/ClassMap.cs similarity index 71% rename from FluentProtobufNet/ClassMap.cs rename to FluentProtobufNet/Mapping/ClassMap.cs index 35d48a5..d215781 100644 --- a/FluentProtobufNet/ClassMap.cs +++ b/FluentProtobufNet/Mapping/ClassMap.cs @@ -3,19 +3,18 @@ using System.Linq; using System.Linq.Expressions; using FluentProtobufNet.Helpers; -using FluentProtobufNet.Mapping; using ProtoBuf.Meta; -namespace FluentProtobufNet +namespace FluentProtobufNet.Mapping { public class ClassMap : IMappingProvider { - public IList Fields { get; set; } + public IList Fields { get; set; } public ClassMap() { - Fields = new List(); + Fields = new List(); } @@ -24,16 +23,16 @@ internal Type EntityType get { return typeof(T); } } - public NameAndFieldNumber Map(Expression> memberExpression, int fieldNumber) + public PropertyMapping Map(Expression> memberExpression, int fieldNumber) { return Map(memberExpression.ToMember(), fieldNumber); } - NameAndFieldNumber Map(Member member, int fieldNumber) + PropertyMapping Map(Member member, int fieldNumber) { - ///­OnMemberMapped(member); + //­OnMemberMapped(member); - var field = new NameAndFieldNumber + var field = new PropertyMapping { Member = member, FieldNumber = fieldNumber, @@ -46,21 +45,21 @@ NameAndFieldNumber Map(Member member, int fieldNumber) } - public NameAndFieldNumber References(Expression> memberExpression, int fieldNumber) + public PropertyMapping References(Expression> memberExpression, int fieldNumber) { return References(memberExpression.ToMember(), fieldNumber); } - public NameAndFieldNumber References(Expression> memberExpression, int fieldNumber) + public PropertyMapping References(Expression> memberExpression, int fieldNumber) { return References(memberExpression.ToMember(), fieldNumber); } - NameAndFieldNumber References(Member member, int fieldNumber) + PropertyMapping References(Member member, int fieldNumber) { //OnMemberMapped(member); - var field = new NameAndFieldNumber + var field = new PropertyMapping { Member = member, FieldNumber = fieldNumber, @@ -90,7 +89,7 @@ public virtual bool CanBeResolvedUsing(RuntimeTypeModel protobufModel) } } - public class NameAndFieldNumber + public class PropertyMapping { public Member Member { get; set; } public int FieldNumber { get; set; } diff --git a/FluentProtobufNet/Mapping/IMappingProvider.cs b/FluentProtobufNet/Mapping/IMappingProvider.cs new file mode 100644 index 0000000..53d3556 --- /dev/null +++ b/FluentProtobufNet/Mapping/IMappingProvider.cs @@ -0,0 +1,13 @@ +using ProtoBuf.Meta; + +namespace FluentProtobufNet +{ + public interface IMappingProvider + { + RuntimeTypeModel GetRuntimeTypeModel(RuntimeTypeModel protobufModel); + // HACK: In place just to keep compatibility until verdict is made + //HibernateMapping GetHibernateMapping(); + //IEnumerable GetIgnoredProperties(); + bool CanBeResolvedUsing(RuntimeTypeModel protobufModel); + } +} \ No newline at end of file diff --git a/FluentProtobufNet/Mapping/ManyToOnePart.cs b/FluentProtobufNet/Mapping/ManyToOnePart.cs deleted file mode 100644 index 395d6bc..0000000 --- a/FluentProtobufNet/Mapping/ManyToOnePart.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FluentProtobufNet.Mapping -{ - public class ManyToOnePart - { - public ManyToOnePart(Type entityType, Member member) - { - - } - } -} diff --git a/FluentProtobufNet/Mapping/PropertyPart.cs b/FluentProtobufNet/Mapping/PropertyPart.cs deleted file mode 100644 index 98d5b74..0000000 --- a/FluentProtobufNet/Mapping/PropertyPart.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace FluentProtobufNet.Mapping -{ - public class PropertyPart - { - public Member Member { get; set; } - public Type Type { get; set; } - - public PropertyPart(Member member, Type type) - { - Member = member; - Type = type; - } - } -} diff --git a/FluentProtobufNet/SubclassMap.cs b/FluentProtobufNet/Mapping/SubclassMap.cs similarity index 86% rename from FluentProtobufNet/SubclassMap.cs rename to FluentProtobufNet/Mapping/SubclassMap.cs index 39d1c7f..6df87fe 100644 --- a/FluentProtobufNet/SubclassMap.cs +++ b/FluentProtobufNet/Mapping/SubclassMap.cs @@ -1,8 +1,9 @@ using System; using System.Linq; +using FluentProtobufNet.Exceptions; using ProtoBuf.Meta; -namespace FluentProtobufNet +namespace FluentProtobufNet.Mapping { public class SubclassMap: ClassMap { @@ -53,11 +54,4 @@ public SubclassFieldIdNotSetException(string message) : base(message) } } } - - public class FieldIdAlreadyUsedException : Exception - { - public FieldIdAlreadyUsedException(int fieldId, MetaType usedBy): base("The field ID " + fieldId + " has already been used by " + usedBy.Name) - { - } - } } \ No newline at end of file diff --git a/FluentProtobufNet/PersistenceModel.cs b/FluentProtobufNet/PersistenceModel.cs index aa0213f..e4e5211 100644 --- a/FluentProtobufNet/PersistenceModel.cs +++ b/FluentProtobufNet/PersistenceModel.cs @@ -3,16 +3,17 @@ using System.Linq; using System.Reflection; using FluentProtobufNet.Helpers; +using FluentProtobufNet.Mapping; using ProtoBuf.Meta; namespace FluentProtobufNet { public class PersistenceModel { - protected readonly IList classProviders = new List(); - protected IDiagnosticLogger log = new NullDiagnosticsLogger(); + protected readonly IList ClassProviders = new List(); + protected IDiagnosticLogger Log = new NullDiagnosticsLogger(); private RuntimeTypeModel _protobufModel; - private IList subclassProviders = new List(); + private readonly IList _subclassProviders = new List(); public void AddMappingsFromAssembly(Assembly assembly) { @@ -22,25 +23,25 @@ public void AddMappingsFromAssembly(Assembly assembly) public void AddMappingsFromSource(ITypeSource source) { source.GetTypes() - .Where(x => IsMappingOf(x)) + .Where(IsMappingOf) .Each(Add); - log.LoadedFluentMappingsFromSource(source); + Log.LoadedFluentMappingsFromSource(source); } - private bool IsMappingOf(Type type) + private static bool IsMappingOf(Type type) { return !type.IsGenericType && typeof(T).IsAssignableFrom(type); } public void Add(IMappingProvider provider) { - classProviders.Add(provider); + ClassProviders.Add(provider); } public void AddSubclassMap(IMappingProvider provider) { - subclassProviders.Add(provider); + _subclassProviders.Add(provider); } public void Add(Type type) @@ -53,7 +54,7 @@ public void Add(Type type) { if (mapping.GetType().BaseType.GetGenericTypeDefinition() == typeof (ClassMap<>)) { - log.FluentMappingDiscovered(type); + Log.FluentMappingDiscovered(type); Add((IMappingProvider)mapping); } else if (mapping.GetType().BaseType.GetGenericTypeDefinition() == typeof (SubclassMap<>)) @@ -68,12 +69,12 @@ public void Add(Type type) public virtual void Configure(Configuration cfg) { - _protobufModel = ProtoBuf.Meta.TypeModel.Create(); - foreach (var classMap in classProviders) + _protobufModel = TypeModel.Create(); + foreach (var classMap in ClassProviders) classMap.GetRuntimeTypeModel(_protobufModel); - var subclassProvidersCopy = subclassProviders.ToList(); - IMappingProvider subclassMap = null; + var subclassProvidersCopy = _subclassProviders.ToList(); + IMappingProvider subclassMap; while ((subclassMap = subclassProvidersCopy.FirstOrDefault(sc => sc.CanBeResolvedUsing(_protobufModel))) != null) { subclassMap.GetRuntimeTypeModel(_protobufModel); @@ -86,66 +87,4 @@ public virtual void Configure(Configuration cfg) cfg.RuntimeTypeModel = _protobufModel; } } - - public class MissingConstructorException : Exception - { - public Type Type { get; set; } - - public MissingConstructorException(Type type) - { - Type = type; - } - } - - public class ReflectHelper - { - public const BindingFlags AnyVisibilityInstance = BindingFlags.Instance | BindingFlags.Public | - BindingFlags.NonPublic; - private static readonly System.Type[] NoClasses = System.Type.EmptyTypes; - - public static ConstructorInfo GetDefaultConstructor(System.Type type) - { - if (IsAbstractClass(type)) - return null; - - try - { - ConstructorInfo constructor = - type.GetConstructor(AnyVisibilityInstance, null, CallingConventions.HasThis, NoClasses, null); - return constructor; - } - catch (Exception e) - { - throw new InstantiationException("A default (no-arg) constructor could not be found for: ", e, type); - } - } - - public static bool IsAbstractClass(System.Type type) - { - return (type.IsAbstract || type.IsInterface); - } - } - - public class InstantiationException : Exception - { - public string Message { get; set; } - public Exception Exception { get; set; } - public Type Type { get; set; } - - public InstantiationException(string message, Exception exception, Type type) - { - Message = message; - Exception = exception; - Type = type; - } - } - - public interface IMappingProvider - { - RuntimeTypeModel GetRuntimeTypeModel(RuntimeTypeModel protobufModel); - // HACK: In place just to keep compatibility until verdict is made - //HibernateMapping GetHibernateMapping(); - //IEnumerable GetIgnoredProperties(); - bool CanBeResolvedUsing(RuntimeTypeModel protobufModel); - } } \ No newline at end of file