Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/NHibernate.Test/CfgTest/ConfigurationSchemaFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,30 @@ public void IgnoreSystemOutOfAppConfig()
Assert.AreEqual(hc.UseReflectionOptimizer, newhc.UseReflectionOptimizer);
}

[Test]
public void ObjectsFactory()
{
Assume.That(TestsContext.ExecutingWithVsTest, Is.False);

var xml =
@"<?xml version='1.0' encoding='utf-8' ?>
<hibernate-configuration xmlns='urn:nhibernate-configuration-2.2'>
<objects-factory type='test'/>
<session-factory>
</session-factory>
</hibernate-configuration>";

HibernateConfiguration hc;
using (var xtr = new XmlTextReader(xml, XmlNodeType.Document, null))
{
hc = new HibernateConfiguration(xtr);
Assert.That(hc.ObjectsFactoryType, Is.Null);
}

hc = HibernateConfiguration.FromAppConfig(xml);
Assert.That(hc.ObjectsFactoryType, Is.EqualTo("test"));
}

[Test]
public void EmptyFactoryNotAllowed()
{
Expand Down
66 changes: 66 additions & 0 deletions src/NHibernate.Test/CfgTest/CustomObjectsFactoryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using NHibernate.Bytecode;
using NUnit.Framework;
using Environment = NHibernate.Cfg.Environment;

namespace NHibernate.Test.CfgTest
{
[TestFixture]
public class CustomObjectsFactoryTest
{
private class MyObjectsFactory : IObjectsFactory
{
public object CreateInstance(System.Type type)
{
throw new NotImplementedException();
}

public object CreateInstance(System.Type type, bool nonPublic)
{
throw new NotImplementedException();
}

public object CreateInstance(System.Type type, params object[] ctorArgs)
{
throw new NotImplementedException();
}
}
private class InvalidObjectsFactory
{
}
private class InvalidNoCtorObjectsFactory : MyObjectsFactory
{
public InvalidNoCtorObjectsFactory(string pizza) {}
}

[Test]
public void WhenNoShortCutUsedThenCanBuildObjectsFactory()
{
var properties = new Dictionary<string, string> { { Environment.PropertyBytecodeProvider, typeof(MyObjectsFactory).AssemblyQualifiedName } };
Assert.That(() => Environment.BuildObjectsFactory(properties), Throws.Nothing);
}

[Test]
public void WhenNoShortCutUsedThenCanBuildInstanceOfConfiguredObjectsFactory()
{
var properties = new Dictionary<string, string> { { Environment.PropertyObjectsFactory, typeof(MyObjectsFactory).AssemblyQualifiedName } };
Assert.That(Environment.BuildObjectsFactory(properties), Is.InstanceOf<MyObjectsFactory>());
}

[Test]
public void WhenInvalidThenThrow()
{
var properties = new Dictionary<string, string> { { Environment.PropertyObjectsFactory, typeof(InvalidObjectsFactory).AssemblyQualifiedName } };
Assert.That(() => Environment.BuildObjectsFactory(properties), Throws.TypeOf<HibernateObjectsFactoryException>());
}

[Test]
public void WhenNoDefaultCtorThenThrow()
{
var properties = new Dictionary<string, string> { { Environment.PropertyObjectsFactory, typeof(InvalidNoCtorObjectsFactory).AssemblyQualifiedName } };
Assert.That(() => Environment.BuildObjectsFactory(properties), Throws.TypeOf<HibernateObjectsFactoryException>()
.And.InnerException.Message.Contains("constructor was not found"));
}
}
}
2 changes: 1 addition & 1 deletion src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public partial class DriverForSubstitutedCommand : IDriver

public DriverForSubstitutedCommand()
{
_driverImplementation = (IDriver) Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(DriverClass);
_driverImplementation = (IDriver) Cfg.Environment.ObjectsFactory.CreateInstance(DriverClass);
}

DbCommand IDriver.GenerateCommand(CommandType type, SqlString sqlString, SqlType[] parameterTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ public class ClientDriverWithParamsStats : IDriver

public ClientDriverWithParamsStats()
{
_driverImplementation = (IDriver) Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(DriverClass);
_driverImplementation = (IDriver) Cfg.Environment.ObjectsFactory.CreateInstance(DriverClass);
}

private static void Inc<T>(T type, IDictionary<T, int> dic)
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Async/Tool/hbm2ddl/SchemaExport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private async Task ExecuteInitializedAsync(Action<string> scriptAction, bool exe
cancellationToken.ThrowIfCancellationRequested();
if (dialect.SupportsSqlBatches)
{
var objFactory = Environment.BytecodeProvider.ObjectsFactory;
var objFactory = Environment.ObjectsFactory;
ScriptSplitter splitter = (ScriptSplitter)objFactory.CreateInstance(typeof(ScriptSplitter), sql);

foreach (string stmt in splitter)
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Async/Tool/hbm2ddl/SchemaUpdate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public partial class SchemaUpdate
{
cfg.SetNamingStrategy(
(INamingStrategy)
Environment.BytecodeProvider.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(args[i].Substring(9))));
Environment.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(args[i].Substring(9))));
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Async/Tool/hbm2ddl/SchemaValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public partial class SchemaValidator
{
cfg.SetNamingStrategy(
(INamingStrategy)
Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(args[i].Substring(9))));
Cfg.Environment.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(args[i].Substring(9))));
}
}
else
Expand Down
12 changes: 5 additions & 7 deletions src/NHibernate/Bytecode/AbstractBytecodeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace NHibernate.Bytecode
{
public abstract class AbstractBytecodeProvider : IBytecodeProvider, IInjectableProxyFactoryFactory, IInjectableCollectionTypeFactoryClass
{
private readonly IObjectsFactory objectsFactory = new ActivatorObjectsFactory();
protected System.Type proxyFactoryFactory;
private ICollectionTypeFactory collectionTypeFactory;
private System.Type collectionTypeFactoryClass = typeof(Type.DefaultCollectionTypeFactory);
Expand All @@ -21,7 +20,7 @@ public virtual IProxyFactoryFactory ProxyFactoryFactory
{
try
{
return (IProxyFactoryFactory) ObjectsFactory.CreateInstance(proxyFactoryFactory);
return (IProxyFactoryFactory) Cfg.Environment.ObjectsFactory.CreateInstance(proxyFactoryFactory);
}
catch (Exception e)
{
Expand All @@ -35,10 +34,9 @@ public virtual IProxyFactoryFactory ProxyFactoryFactory

public abstract IReflectionOptimizer GetReflectionOptimizer(System.Type clazz, IGetter[] getters, ISetter[] setters);

public virtual IObjectsFactory ObjectsFactory
{
get { return objectsFactory; }
}
// Since 5.2
[Obsolete("Please use NHibernate.Cfg.Environment.ObjectsFactory instead")]
public virtual IObjectsFactory ObjectsFactory => Cfg.Environment.ObjectsFactory;

public virtual ICollectionTypeFactory CollectionTypeFactory
{
Expand All @@ -49,7 +47,7 @@ public virtual ICollectionTypeFactory CollectionTypeFactory
try
{
collectionTypeFactory =
(ICollectionTypeFactory) ObjectsFactory.CreateInstance(collectionTypeFactoryClass);
(ICollectionTypeFactory) Cfg.Environment.ObjectsFactory.CreateInstance(collectionTypeFactoryClass);
}
catch (Exception e)
{
Expand Down
18 changes: 18 additions & 0 deletions src/NHibernate/Bytecode/HibernateObjectsFactoryException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Runtime.Serialization;

namespace NHibernate.Bytecode
{
/// <summary>
/// Thrown if NHibernate can't instantiate the <see cref="IObjectsFactory"/> type.
/// </summary>
[Serializable]
public class HibernateObjectsFactoryException : HibernateException
{
public HibernateObjectsFactoryException() {}
public HibernateObjectsFactoryException(string message) : base(message) {}
public HibernateObjectsFactoryException(string message, Exception inner) : base(message, inner) {}

protected HibernateObjectsFactoryException(SerializationInfo info, StreamingContext context) : base(info, context) {}
}
}
3 changes: 3 additions & 0 deletions src/NHibernate/Bytecode/IBytecodeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using NHibernate.Properties;

namespace NHibernate.Bytecode
Expand Down Expand Up @@ -26,6 +27,8 @@ public interface IBytecodeProvider
/// <remarks>
/// For entities <see cref="IReflectionOptimizer"/> and its implementations.
/// </remarks>
// Since 5.2
[Obsolete("Please use NHibernate.Cfg.Environment.ObjectsFactory instead")]
IObjectsFactory ObjectsFactory { get; }

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Cfg/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1902,7 +1902,7 @@ public void SetListeners(ListenerType type, string[] listenerClasses)
{
try
{
listeners[i] = Environment.BytecodeProvider.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(listenerClasses[i]));
listeners[i] = Environment.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(listenerClasses[i]));
}
catch (Exception e)
{
Expand Down
3 changes: 3 additions & 0 deletions src/NHibernate/Cfg/ConfigurationSchema/CfgXmlHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static CfgXmlHelper()
nsMgr.AddNamespace(CfgNamespacePrefix, CfgSchemaXMLNS);

ByteCodeProviderExpression = XPathExpression.Compile(RootPrefixPath + "bytecode-provider", nsMgr);
ObjectsFactoryExpression = XPathExpression.Compile(RootPrefixPath + "objects-factory", nsMgr);
ReflectionOptimizerExpression = XPathExpression.Compile(RootPrefixPath + "reflection-optimizer", nsMgr);
SessionFactoryExpression = XPathExpression.Compile(RootPrefixPath + "session-factory", nsMgr);
SessionFactoryPropertiesExpression = XPathExpression.Compile(RootPrefixPath + "session-factory/" + ChildPrefixPath + "property", nsMgr);
Expand All @@ -47,6 +48,8 @@ static CfgXmlHelper()

/// <summary>XPath expression for bytecode-provider property.</summary>
public static readonly XPathExpression ByteCodeProviderExpression;
/// <summary>XPath expression for objects-factory property.</summary>
public static readonly XPathExpression ObjectsFactoryExpression;
/// <summary>XPath expression for reflection-optimizer property.</summary>
public static readonly XPathExpression ReflectionOptimizerExpression;
/// <summary>XPath expression for session-factory whole node.</summary>
Expand Down
25 changes: 25 additions & 0 deletions src/NHibernate/Cfg/ConfigurationSchema/HibernateConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private XmlReaderSettings GetSettings()
private void Parse(XPathNavigator navigator, bool fromAppConfig)
{
ParseByteCodeProvider(navigator, fromAppConfig);
ParseObjectsFactory(navigator, fromAppConfig);
ParseReflectionOptimizer(navigator, fromAppConfig);
XPathNavigator xpn = navigator.SelectSingleNode(CfgXmlHelper.SessionFactoryExpression);
if (xpn != null)
Expand Down Expand Up @@ -110,6 +111,23 @@ private void ParseByteCodeProvider(XPathNavigator navigator, bool fromAppConfig)
}
}

private void ParseObjectsFactory(XPathNavigator navigator, bool fromAppConfig)
{
var xpn = navigator.SelectSingleNode(CfgXmlHelper.ObjectsFactoryExpression);
if (xpn != null)
{
if (fromAppConfig)
{
xpn.MoveToFirstAttribute();
ObjectsFactoryType = xpn.Value;
}
else
{
LogWarnIgnoredProperty("objects-factory");
}
}
}

private static void LogWarnIgnoredProperty(string propName)
{
if (log.IsWarnEnabled())
Expand Down Expand Up @@ -143,6 +161,13 @@ public string ByteCodeProviderType
get { return byteCodeProviderType; }
}

/// <summary>
/// Value for objects-factory system property.
/// </summary>
/// <remarks>Default value <see langword="null" />.</remarks>
// 6.0 TODO add to IHibernateConfiguration
public string ObjectsFactoryType { get; private set; }

private bool useReflectionOptimizer = true;
/// <summary>
/// Value for reflection-optimizer system property.
Expand Down
61 changes: 61 additions & 0 deletions src/NHibernate/Cfg/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public static string Version
public const string PropertyBytecodeProvider = "bytecode.provider";
public const string PropertyUseReflectionOptimizer = "use_reflection_optimizer";

/// <summary>
/// Set the <see cref="IObjectsFactory"/> used to instantiate NHibernate's objects.
/// </summary>
public const string PropertyObjectsFactory = "objects_factory";

public const string UseProxyValidator = "use_proxy_validator";
public const string ProxyFactoryFactoryClass = "proxyfactory.factory_class";

Expand Down Expand Up @@ -306,6 +311,10 @@ public static void InitializeGlobalProperties(IHibernateConfiguration config)
HibernateConfiguration = config;
GlobalProperties[PropertyBytecodeProvider] = config.ByteCodeProviderType;
GlobalProperties[PropertyUseReflectionOptimizer] = config.UseReflectionOptimizer.ToString();
if (config is HibernateConfiguration nhConfig)
{
GlobalProperties[PropertyObjectsFactory] = nhConfig.ObjectsFactoryType;
}
if (config.SessionFactory != null)
{
foreach (var kvp in config.SessionFactory.Properties)
Expand All @@ -322,6 +331,7 @@ public static void InitializeGlobalProperties(IHibernateConfiguration config)
VerifyProperties(GlobalProperties);

BytecodeProviderInstance = BuildBytecodeProvider(GlobalProperties);
ObjectsFactory = BuildObjectsFactory(GlobalProperties);
EnableReflectionOptimizer = PropertiesHelper.GetBoolean(PropertyUseReflectionOptimizer, GlobalProperties);

if (EnableReflectionOptimizer)
Expand Down Expand Up @@ -381,6 +391,16 @@ public static IBytecodeProvider BytecodeProvider
set { BytecodeProviderInstance = value; }
}

/// <summary>
/// NHibernate's object instantiator.
/// </summary>
/// <remarks>
/// This should only be set before a configuration object
/// is created, otherwise the change may not take effect.
/// For entities see <see cref="IReflectionOptimizer"/> and its implementations.
/// </remarks>
public static IObjectsFactory ObjectsFactory { get; set; } = new ActivatorObjectsFactory();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid a possible breaking change, we should default to using BytecodeProvider.ObjectsFactory here. But for completeness, we should also use the objects factory to create the byte-code provider...

I may add a commit sorting this out.


/// <summary>
/// Whether to enable the use of reflection optimizer
/// </summary>
Expand Down Expand Up @@ -420,6 +440,18 @@ private static IBytecodeProvider BuildBytecodeProvider(string providerName)
}
}

public static IObjectsFactory BuildObjectsFactory(IDictionary<string, string> properties)
{
var typeAssemblyQualifiedName = PropertiesHelper.GetString(PropertyObjectsFactory, properties, null);
if (typeAssemblyQualifiedName == null)
{
log.Info("Objects factory class : {0}", typeof(ActivatorObjectsFactory));
return new ActivatorObjectsFactory();
}
log.Info("Custom objects factory class : {0}", typeAssemblyQualifiedName);
return CreateCustomObjectsFactory(typeAssemblyQualifiedName);
}

private static IBytecodeProvider CreateCustomBytecodeProvider(string assemblyQualifiedName)
{
try
Expand Down Expand Up @@ -447,5 +479,34 @@ private static IBytecodeProvider CreateCustomBytecodeProvider(string assemblyQua
throw new HibernateByteCodeException("Unable to create the instance of Bytecode provider; check inner exception for detail", e);
}
}

private static IObjectsFactory CreateCustomObjectsFactory(string assemblyQualifiedName)
{
try
{
var type = ReflectHelper.ClassForName(assemblyQualifiedName);
try
{
return (IObjectsFactory) Activator.CreateInstance(type);
}
catch (MissingMethodException ex)
{
throw new HibernateObjectsFactoryException("Public constructor was not found for " + type, ex);
}
catch (InvalidCastException ex)
{
throw new HibernateObjectsFactoryException(type + "Type does not implement " + typeof(IObjectsFactory), ex);
}
catch (Exception ex)
{
throw new HibernateObjectsFactoryException("Unable to instantiate: " + type, ex);
}
}
catch (Exception e)
{
throw new HibernateObjectsFactoryException("Unable to create the instance of objects factory; check inner exception for detail", e);
}
}

}
}
Loading