-
Notifications
You must be signed in to change notification settings - Fork 862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DynamoDBEntryConversion AOT compatibility #3300
base: v4-development
Are you sure you want to change the base?
Changes from 10 commits
b09b580
08cc134
7072a05
39d798e
0482031
b8d7219
db0e727
072e208
60d91bb
b512f50
3e3fc81
6144c3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,11 +15,11 @@ | |
|
||
using System; | ||
using System.Collections; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using Amazon.DynamoDBv2.DataModel; | ||
using Amazon.DynamoDBv2.DocumentModel; | ||
using Amazon.Util.Internal; | ||
|
||
#if NETSTANDARD | ||
using Amazon.Runtime.Internal.Util; | ||
|
@@ -71,9 +71,6 @@ internal enum ConversionSchema | |
/// A collection of converters capable of converting between | ||
/// .NET and DynamoDB objects. | ||
/// </summary> | ||
#if NET8_0_OR_GREATER | ||
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(Amazon.DynamoDBv2.Custom.Internal.InternalConstants.RequiresUnreferencedCodeMessage)] | ||
#endif | ||
public class DynamoDBEntryConversion | ||
{ | ||
#region Static members | ||
|
@@ -360,6 +357,7 @@ internal IEnumerable<DynamoDBEntry> ConvertToEntries<T>(IEnumerable<T> values) | |
//foreach (var value in values) | ||
// yield return ConvertToEntry(value); | ||
} | ||
|
||
internal IEnumerable<object> ConvertFromEntries(Type elementType, IEnumerable<DynamoDBEntry> entries) | ||
{ | ||
if (entries == null) throw new ArgumentNullException("entries"); | ||
|
@@ -368,6 +366,14 @@ internal IEnumerable<object> ConvertFromEntries(Type elementType, IEnumerable<Dy | |
yield return ConvertFromEntry(elementType, entry); | ||
} | ||
|
||
internal IEnumerable<T> ConvertFromEntries<T>(IEnumerable<DynamoDBEntry> entries) | ||
{ | ||
if (entries == null) throw new ArgumentNullException("entries"); | ||
|
||
foreach (var entry in entries) | ||
yield return ConvertFromEntry<T>(entry); | ||
} | ||
|
||
internal PrimitiveList ItemsToPrimitiveList(IEnumerable items) | ||
{ | ||
var inputType = items.GetType(); | ||
|
@@ -384,59 +390,24 @@ internal PrimitiveList ItemsToPrimitiveList(IEnumerable items) | |
private ConverterCache ConverterCache = new ConverterCache(); | ||
private ConversionSchema OriginalConversion; | ||
|
||
internal void AddConverter(Converter converter) | ||
internal void AddConverterFactory(ConverterFactory factory) | ||
{ | ||
ConverterCache.AddConverter(converter, this); | ||
if (IsImmutable) | ||
throw new InvalidOperationException("Adding converters to immutable conversion is not supported. The conversion must be cloned first."); | ||
|
||
ConverterCache.AddConverterFactory(factory); | ||
} | ||
|
||
private void SetV1Converters() | ||
{ | ||
AddConverter(new ByteConverterV1()); | ||
AddConverter(new SByteConverterV1()); | ||
AddConverter(new UInt16ConverterV1()); | ||
AddConverter(new Int16ConverterV1()); | ||
AddConverter(new UInt32ConverterV1()); | ||
AddConverter(new Int32ConverterV1()); | ||
AddConverter(new UInt64ConverterV1()); | ||
AddConverter(new Int64ConverterV1()); | ||
AddConverter(new SingleConverterV1()); | ||
AddConverter(new DoubleConverterV1()); | ||
AddConverter(new DecimalConverterV1()); | ||
AddConverter(new CharConverterV1()); | ||
AddConverter(new StringConverterV1()); | ||
AddConverter(new DateTimeConverterV1()); | ||
AddConverter(new GuidConverterV1()); | ||
AddConverter(new BytesConverterV1()); | ||
AddConverter(new MemoryStreamConverterV1()); | ||
AddConverter(new EnumConverterV1()); | ||
AddConverter(new BoolConverterV1()); | ||
AddConverter(new PrimitiveCollectionConverterV1()); | ||
AddConverter(new DictionaryConverterV1()); | ||
AddConverterFactory(new DefaultConverterFactoryV1(this)); | ||
AddConverterFactory(new CollectionConverterFactoryV1(this)); | ||
} | ||
|
||
private void SetV2Converters() | ||
{ | ||
AddConverter(new ByteConverterV2()); | ||
AddConverter(new SByteConverterV2()); | ||
AddConverter(new UInt16ConverterV2()); | ||
AddConverter(new Int16ConverterV2()); | ||
AddConverter(new UInt32ConverterV2()); | ||
AddConverter(new Int32ConverterV2()); | ||
AddConverter(new UInt64ConverterV2()); | ||
AddConverter(new Int64ConverterV2()); | ||
AddConverter(new SingleConverterV2()); | ||
AddConverter(new DoubleConverterV2()); | ||
AddConverter(new DecimalConverterV2()); | ||
AddConverter(new CharConverterV2()); | ||
AddConverter(new StringConverterV2()); | ||
AddConverter(new DateTimeConverterV2()); | ||
AddConverter(new GuidConverterV2()); | ||
AddConverter(new BytesConverterV2()); | ||
AddConverter(new MemoryStreamConverterV2()); | ||
AddConverter(new DictionaryConverterV2()); | ||
AddConverter(new EnumConverterV2()); | ||
AddConverter(new BoolConverterV2()); | ||
AddConverter(new CollectionConverterV2()); | ||
AddConverterFactory(new DefaultConverterFactoryV2(this)); | ||
AddConverterFactory(new CollectionConverterFactoryV2(this)); | ||
} | ||
|
||
// Converts items to Primitives. | ||
|
@@ -468,14 +439,30 @@ private IEnumerable<Primitive> ToPrimitives(IEnumerable items, Type elementType) | |
#endregion | ||
} | ||
|
||
internal abstract class Converter | ||
internal abstract class ConverterFactory | ||
{ | ||
/// <summary> | ||
/// Returns all types for which it can be used. | ||
/// </summary> | ||
/// <returns></returns> | ||
public abstract IEnumerable<Type> GetTargetTypes(); | ||
private readonly DynamoDBEntryConversion _conversion; | ||
|
||
protected ConverterFactory(DynamoDBEntryConversion conversion) | ||
{ | ||
_conversion = conversion; | ||
} | ||
|
||
public Converter GetConverter(Type type) | ||
{ | ||
var converter = CreateConverter(type); | ||
|
||
if(converter != null) | ||
converter.Conversion = _conversion; | ||
|
||
return converter; | ||
} | ||
|
||
protected abstract Converter CreateConverter(Type type); | ||
} | ||
|
||
internal abstract class Converter | ||
{ | ||
/// <summary> | ||
/// Conversion that this converter is part of. | ||
/// This field is set by DynamoDBEntryConversion when the Converter | ||
|
@@ -651,19 +638,6 @@ public virtual bool TryFrom(Document d, Type targetType, out object result) | |
|
||
internal abstract class Converter<T> : Converter | ||
{ | ||
public override IEnumerable<Type> GetTargetTypes() | ||
{ | ||
var type = typeof(T); | ||
yield return type; | ||
|
||
if (type.IsValueType) | ||
{ | ||
//yield return typeof(Nullable<T>); | ||
var nullableType = typeof(Nullable<>).MakeGenericType(type); | ||
yield return nullableType; | ||
} | ||
} | ||
|
||
public override bool TryTo(object value, out DynamoDBBool b) | ||
{ | ||
return TryTo((T)value, out b); | ||
|
@@ -714,60 +688,60 @@ protected virtual bool TryTo(T value, out Document d) | |
public override bool TryFrom(DynamoDBBool b, Type targetType, out object result) | ||
{ | ||
T t; | ||
var output = TryFrom(b, targetType, out t); | ||
var output = TryFrom(b, out t); | ||
result = t; | ||
return output; | ||
} | ||
public override bool TryFrom(Primitive p, Type targetType, out object result) | ||
{ | ||
T t; | ||
var output = TryFrom(p, targetType, out t); | ||
var output = TryFrom(p, out t); | ||
result = t; | ||
return output; | ||
} | ||
public override bool TryFrom(PrimitiveList pl, Type targetType, out object result) | ||
{ | ||
T t; | ||
var output = TryFrom(pl, targetType, out t); | ||
var output = TryFrom(pl, out t); | ||
result = t; | ||
return output; | ||
} | ||
public override bool TryFrom(DynamoDBList l, Type targetType, out object result) | ||
{ | ||
T t; | ||
var output = TryFrom(l, targetType, out t); | ||
var output = TryFrom(l, out t); | ||
result = t; | ||
return output; | ||
} | ||
public override bool TryFrom(Document d, Type targetType, out object result) | ||
{ | ||
T t; | ||
var output = TryFrom(d, targetType, out t); | ||
var output = TryFrom(d, out t); | ||
result = t; | ||
return output; | ||
} | ||
|
||
protected virtual bool TryFrom(DynamoDBBool b, Type targetType, out T result) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having a separate The only Converter to actually use it is (Not a public API, so no breaking changes here) |
||
protected virtual bool TryFrom(DynamoDBBool b, out T result) | ||
{ | ||
result = default(T); | ||
return false; | ||
} | ||
protected virtual bool TryFrom(Primitive p, Type targetType, out T result) | ||
protected virtual bool TryFrom(Primitive p, out T result) | ||
{ | ||
result = default(T); | ||
return false; | ||
} | ||
protected virtual bool TryFrom(PrimitiveList pl, Type targetType, out T result) | ||
protected virtual bool TryFrom(PrimitiveList pl, out T result) | ||
{ | ||
result = default(T); | ||
return false; | ||
} | ||
protected virtual bool TryFrom(DynamoDBList l, Type targetType, out T result) | ||
protected virtual bool TryFrom(DynamoDBList l, out T result) | ||
{ | ||
result = default(T); | ||
return false; | ||
} | ||
protected virtual bool TryFrom(Document d, Type targetType, out T result) | ||
protected virtual bool TryFrom(Document d, out T result) | ||
{ | ||
result = default(T); | ||
return false; | ||
|
@@ -777,29 +751,20 @@ protected virtual bool TryFrom(Document d, Type targetType, out T result) | |
internal class ConverterCache | ||
{ | ||
private static Type EnumType = typeof(Enum); | ||
private Dictionary<Type, Converter> Cache = new Dictionary<Type, Converter>(); | ||
private readonly ConcurrentDictionary<Type, Converter> Cache = new ConcurrentDictionary<Type, Converter>(); | ||
private readonly List<ConverterFactory> Factories = new List<ConverterFactory>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously all the converters were created upfront, but now they are created lazily, when requested. Therefore, ConcurrentDictionary is used for cache, as it is possible that converter is requested from multiple threads at the same time. |
||
|
||
public bool HasConverter(Type type) | ||
{ | ||
Converter converter; | ||
return TryGetConverter(type, out converter); | ||
return TryGetConverter(type, out _); | ||
} | ||
public void AddConverter(Converter converter, DynamoDBEntryConversion conversion) | ||
{ | ||
if (converter == null) | ||
throw new ArgumentNullException("converter"); | ||
if (conversion == null) | ||
throw new ArgumentNullException("conversion"); | ||
|
||
if (conversion.IsImmutable) | ||
throw new InvalidOperationException("Adding converters to immutable conversion is not supported. The conversion must be cloned first."); | ||
public void AddConverterFactory(ConverterFactory factory) | ||
{ | ||
if (factory == null) | ||
throw new ArgumentNullException(nameof(factory)); | ||
|
||
converter.Conversion = conversion; | ||
var types = converter.GetTargetTypes(); | ||
foreach (var type in types) | ||
{ | ||
Cache[type] = converter; | ||
} | ||
Factories.Add(factory); | ||
} | ||
|
||
public Converter GetConverter(Type type) | ||
|
@@ -817,9 +782,23 @@ public bool TryGetConverter(Type type, out Converter converter) | |
|
||
// all enums use the same converter, one for Enum | ||
if (type.IsEnum) | ||
return Cache.TryGetValue(EnumType, out converter); | ||
type = EnumType; | ||
|
||
return Cache.TryGetValue(type, out converter); | ||
if (Cache.TryGetValue(type, out converter)) | ||
return converter != null; | ||
|
||
foreach (var factory in Factories) | ||
{ | ||
converter = factory.GetConverter(type); | ||
if (converter != null) | ||
{ | ||
Cache[type] = converter; | ||
return true; | ||
} | ||
} | ||
|
||
Cache[type] = null; | ||
return false; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an existing generic method ConvertFromEntry<T>, but there was no generic method for multiple entries