Skip to content

Commit 600b9ed

Browse files
committed
Avoid some cases of Type -> string -> Type conversion in Mapping By Code
1 parent f0f2a53 commit 600b9ed

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

src/NHibernate/Mapping/ByCode/Impl/TypeNameUtil.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public static class TypeNameUtil
88
public static string GetNhTypeName(this System.Type type)
99
{
1010
string typeName;
11-
IType nhType = TypeFactory.HeuristicType(type.AssemblyQualifiedName);
11+
IType nhType = TypeFactory.HeuristicType(type);
1212
if (nhType != null)
1313
{
1414
typeName = nhType.Name;
@@ -68,4 +68,4 @@ private static string GetTypeNameForMapping(System.Type type)
6868
return type.Name;
6969
}
7070
}
71-
}
71+
}

src/NHibernate/Type/TypeFactory.cs

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,22 @@ public static IType HeuristicType(string typeName)
522522
return HeuristicType(typeName, null);
523523
}
524524

525+
/// <summary>
526+
/// Uses heuristics to deduce a NHibernate type given a string naming the
527+
/// type.
528+
/// </summary>
529+
/// <param name="type"></param>
530+
/// <returns>An instance of <c>NHibernate.Type.IType</c></returns>
531+
/// <remarks>
532+
/// We check to see if it implements IType, ICompositeUserType, IUserType, ILifecycle (Association), or
533+
/// IPersistentEnum. If none of those are implemented then we will serialize the Type to the
534+
/// database using NHibernate.Type.SerializableType(typeName)
535+
/// </remarks>
536+
public static IType HeuristicType(System.Type type)
537+
{
538+
return HeuristicType(type, parameters: null, length: null);
539+
}
540+
525541
/// <summary>
526542
/// Uses heuristics to deduce a NHibernate type given a string naming the type.
527543
/// </summary>
@@ -532,7 +548,7 @@ public static IType HeuristicType(string typeName, IDictionary<string, string> p
532548
{
533549
return HeuristicType(typeName, parameters, null);
534550
}
535-
551+
536552
/// <summary>
537553
/// Uses heuristics to deduce a NHibernate type given a string naming the type.
538554
/// </summary>
@@ -546,46 +562,64 @@ public static IType HeuristicType(string typeName, IDictionary<string, string> p
546562

547563
if (type != null)
548564
return type;
549-
565+
550566
string[] parsedTypeName;
551-
TypeClassification typeClassification = GetTypeClassification(typeName);
567+
var typeClassification = GetTypeClassification(typeName);
552568
if (typeClassification == TypeClassification.LengthOrScale)
569+
{
553570
parsedTypeName = typeName.Split(LengthSplit);
571+
if (!int.TryParse(parsedTypeName[1], out int parsedLength))
572+
{
573+
throw new MappingException($"Could not parse length value '{parsedTypeName[1]}' as int for type '{typeName}'");
574+
}
575+
length = parsedLength;
576+
}
554577
else
555578
parsedTypeName = typeClassification == TypeClassification.PrecisionScale ? typeName.Split(PrecisionScaleSplit) : new[] { typeName };
556579

557-
558580
System.Type typeClass;
559581
try
560582
{
561583
typeClass = ReflectHelper.ClassForName(parsedTypeName[0]); //typeName);
562584
}
563585
catch (Exception)
564586
{
565-
typeClass = null;
587+
return null;
566588
}
589+
return HeuristicType(typeClass, parameters, length, false);
590+
}
567591

568-
if (typeClass == null)
569-
return null;
570-
592+
private static IType HeuristicType(System.Type typeClass, IDictionary<string, string> parameters, int? length, bool tryBasic = true)
593+
{
594+
if(tryBasic)
595+
{
596+
IType type = Basic(typeClass.AssemblyQualifiedName, parameters);
597+
598+
if (type != null)
599+
return type;
600+
}
571601
if (typeof(IType).IsAssignableFrom(typeClass))
572602
{
573603
try
574604
{
575-
type = (IType) Environment.ObjectsFactory.CreateInstance(typeClass);
605+
var type = (IType) Environment.ObjectsFactory.CreateInstance(typeClass);
606+
InjectParameters(type, parameters);
607+
608+
var obsolete = typeClass.GetCustomAttribute<ObsoleteAttribute>(false);
609+
if (obsolete != null)
610+
{
611+
_log.Warn("{0} is obsolete. {1}", typeClass.AssemblyQualifiedName, obsolete.Message);
612+
}
613+
return type;
576614
}
577-
catch (Exception e)
615+
catch (HibernateException)
578616
{
579-
throw new MappingException("Could not instantiate IType " + typeClass.Name + ": " + e, e);
617+
throw;
580618
}
581-
InjectParameters(type, parameters);
582-
583-
var obsolete = typeClass.GetCustomAttribute<ObsoleteAttribute>(false);
584-
if (obsolete != null)
619+
catch (Exception e)
585620
{
586-
_log.Warn("{0} is obsolete. {1}", typeName, obsolete.Message);
621+
throw new MappingException("Could not instantiate IType " + typeClass.Name + ": " + e, e);
587622
}
588-
return type;
589623
}
590624
if (typeof(ICompositeUserType).IsAssignableFrom(typeClass))
591625
{
@@ -603,19 +637,16 @@ public static IType HeuristicType(string typeName, IDictionary<string, string> p
603637
var unwrapped = typeClass.UnwrapIfNullable();
604638
if (unwrapped.IsEnum)
605639
{
606-
return (IType) Activator.CreateInstance(typeof (EnumType<>).MakeGenericType(unwrapped));
640+
return (IType) Activator.CreateInstance(typeof(EnumType<>).MakeGenericType(unwrapped));
607641
}
608642

609643
if (!typeClass.IsSerializable)
610644
return null;
611645

612-
if (typeClassification == TypeClassification.LengthOrScale)
613-
return GetSerializableType(typeClass, Int32.Parse(parsedTypeName[1]));
614-
615646
if (length.HasValue)
616647
return GetSerializableType(typeClass, length.Value);
617648

618-
return GetSerializableType(typeClass);
649+
return GetSerializedOrBasicType(typeClass);
619650
}
620651

621652
/// <summary>
@@ -683,14 +714,19 @@ private static NullableType GetType(NullableType defaultUnqualifiedType, byte pr
683714
/// </para>
684715
/// </remarks>
685716
public static NullableType GetSerializableType(System.Type serializableType)
717+
{
718+
return (NullableType) GetSerializedOrBasicType(serializableType);
719+
}
720+
721+
private static IType GetSerializedOrBasicType(System.Type serializableType)
686722
{
687723
var key = serializableType.AssemblyQualifiedName;
688724

689725
// The value factory may be run concurrently, but only one resulting value will be yielded to all threads.
690726
// So we should add the type with its other key in a later operation in order to ensure we cache the same
691727
// instance for both keys.
692728
var added = false;
693-
var type = (NullableType)typeByTypeOfName.GetOrAdd(
729+
var type = typeByTypeOfName.GetOrAdd(
694730
key,
695731
k =>
696732
{

0 commit comments

Comments
 (0)