Skip to content

Commit

Permalink
Fix object deserialization when type is not assignable
Browse files Browse the repository at this point in the history
  • Loading branch information
lbnascimento committed Dec 5, 2022
1 parent 6d9ac62 commit d72c677
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 2 deletions.
30 changes: 30 additions & 0 deletions LiteDB.Tests/Mapper/Mapper_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using FluentAssertions;
using System;
using System.Reflection;
using Xunit;

namespace LiteDB.Tests.Mapper
Expand All @@ -17,5 +19,33 @@ public void ToDocument_ReturnsNull_WhenFail()
var doc2 = _mapper.ToDocument(typeof(int[]), array);
doc2.Should<BsonDocument>().Be(null);
}

[Fact]
public void Class_Not_Assignable()
{
using (var db = new LiteDatabase(":memory:"))
{
var col = db.GetCollection<MyClass>("Test");
col.Insert(new MyClass { Id = 1, Member = null });
var type = typeof(OtherClass);
var typeName = type.FullName + ", " + type.GetTypeInfo().Assembly.GetName().Name;

db.Execute($"update Test set Member = {{_id: 1, Name: null, _type: \"{typeName}\"}} where _id = 1");

Func<MyClass> func = (() => col.FindById(1));
func.Should().Throw<LiteException>();
}
}

public class MyClass
{
public int Id { get; set; }
public MyClass Member { get; set; }
}

public class OtherClass
{
public string Name { get; set; }
}
}
}
7 changes: 5 additions & 2 deletions LiteDB/Client/Mapper/BsonMapper.Deserialize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,12 @@ public object Deserialize(Type type, BsonValue value)
// test if value is object and has _type
if (doc.TryGetValue("_type", out var typeField) && typeField.IsString)
{
type = _typeNameBinder.GetType(typeField.AsString);
var actualType = _typeNameBinder.GetType(typeField.AsString);

if (type == null) throw LiteException.InvalidTypedName(typeField.AsString);
if (actualType == null) throw LiteException.InvalidTypedName(typeField.AsString);
if (!type.IsAssignableFrom(actualType)) throw LiteException.DataTypeNotAssignable(type.FullName, actualType.FullName);

type = actualType;
}
// when complex type has no definition (== typeof(object)) use Dictionary<string, object> to better set values
else if (type == typeof(object))
Expand Down
6 changes: 6 additions & 0 deletions LiteDB/Utils/LiteException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class LiteException : Exception
public const int INVALID_INITIALSIZE = 211;
public const int INVALID_NULL_CHAR_STRING = 212;
public const int INVALID_FREE_SPACE_PAGE = 213;
public const int DATA_TYPE_NOT_ASSIGNABLE = 214;

#endregion

Expand Down Expand Up @@ -306,6 +307,11 @@ internal static LiteException InvalidFreeSpacePage(uint pageID, int freeBytes, i
return new LiteException(INVALID_FREE_SPACE_PAGE, $"An operation that would corrupt page {pageID} was prevented. The operation required {length} free bytes, but the page had only {freeBytes} available.");
}

internal static LiteException DataTypeNotAssignable(string type1, string type2)
{
return new LiteException(DATA_TYPE_NOT_ASSIGNABLE, $"Data type {type1} is not assignable from data type {type2}");
}

#endregion
}
}

0 comments on commit d72c677

Please sign in to comment.