Ok, below is what I have at the moment and it is working. What I want is to
be able to override the default tuplizer with a customized version that does
exactly everything that the existing tuplizer does, but rather than looking
for the default no-args constructor I want it to first check to see whether
my IoC container can provide the instance. It feels a little awkward to have
to change the IInstantiator AND the ITuplizer, to me it makes sense that the
IInstantiator should be responsible for making decisions on whether or not a
no-args constructor should be available. But at the moment that check is
spread out across both classes. Does it sound sensible to change that?
I have had to basically copy the code from PocoEntityTuplizer verbatim,
because I don't know enough about the nh internals to know whether I need
the code that relates to optimizers, instrumented fields, etc:
public class IocProxyFactoryFactory : IProxyFactoryFactory
{
public IProxyFactory BuildProxyFactory()
{
return new ProxyFactory();
}
public IProxyValidator ProxyValidator
{
get { return new IocDynProxyTypeValidator(); }
}
}
public class IocDynProxyTypeValidator : DynProxyTypeValidator
{
protected override void CheckHasVisibleDefaultConstructor(Type type)
{
if (IoC.IsInitialized &&
!IoC.Container.Kernel.HasComponent(type))
base.CheckHasVisibleDefaultConstructor(type);
}
}
public class IocTuplizer : AbstractEntityTuplizer
{
private static readonly ILog log =
LogManager.GetLogger(typeof(PocoEntityTuplizer));
private readonly System.Type mappedClass;
private readonly System.Type proxyInterface;
private readonly bool islifecycleImplementor;
private readonly bool isValidatableImplementor;
private readonly HashedSet<string> lazyPropertyNames = new
HashedSet<string>();
private readonly IReflectionOptimizer optimizer;
private readonly IProxyValidator proxyValidator;
public IocTuplizer(EntityMetamodel entityMetamodel, PersistentClass
mappedEntity)
: base(entityMetamodel, mappedEntity)
{
mappedClass = mappedEntity.MappedClass;
proxyInterface = mappedEntity.ProxyInterface;
islifecycleImplementor =
typeof(ILifecycle).IsAssignableFrom(mappedClass);
isValidatableImplementor =
typeof(IValidatable).IsAssignableFrom(mappedClass);
foreach (Mapping.Property property in
mappedEntity.PropertyClosureIterator)
{
if (property.IsLazy)
lazyPropertyNames.Add(property.Name);
}
if (hasCustomAccessors ||
!Cfg.Environment.UseReflectionOptimizer || (IoC.IsInitialized &&
IoC.Container.Kernel.HasComponent(mappedClass)))
{
optimizer = null;
}
else
{
optimizer =
Cfg.Environment.BytecodeProvider.GetReflectionOptimizer(mappedClass,
getters, setters);
}
proxyValidator =
Cfg.Environment.BytecodeProvider.ProxyFactoryFactory.ProxyValidator;
}
public override System.Type ConcreteProxyClass
{
get { return proxyInterface; }
}
public override bool IsInstrumented
{
get { return
FieldInterceptionHelper.IsInstrumented(MappedClass); }
}
public override System.Type MappedClass
{
get { return mappedClass; }
}
protected override IGetter BuildPropertyGetter(Property
mappedProperty, PersistentClass mappedEntity)
{
return mappedProperty.GetGetter(mappedEntity.MappedClass);
}
protected override ISetter BuildPropertySetter(Property
mappedProperty, PersistentClass mappedEntity)
{
return mappedProperty.GetSetter(mappedEntity.MappedClass);
}
protected override IInstantiator BuildInstantiator(PersistentClass
persistentClass)
{
return new IocInstantiator(persistentClass, null);
}
protected override IProxyFactory BuildProxyFactory(PersistentClass
persistentClass, IGetter idGetter, ISetter idSetter)
{
bool needAccesorCheck = true; // NH specific (look the comment
below)
// determine the id getter and setter methods from the proxy
interface (if any)
// determine all interfaces needed by the resulting proxy
var proxyInterfaces = new HashedSet<System.Type> {
typeof(INHibernateProxy) };
System.Type _mappedClass = persistentClass.MappedClass;
System.Type _proxyInterface = persistentClass.ProxyInterface;
if (_proxyInterface != null &&
!_mappedClass.Equals(_proxyInterface))
{
if (!_proxyInterface.IsInterface)
{
throw new MappingException("proxy must be either an
interface, or the class itself: " + EntityName);
}
needAccesorCheck = false; // NH (the proxy is an interface
all properties can be overridden)
proxyInterfaces.Add(_proxyInterface);
}
if (_mappedClass.IsInterface)
{
needAccesorCheck = false; // NH (the mapped class is an
interface all properties can be overridden)
proxyInterfaces.Add(_mappedClass);
}
foreach (Subclass subclass in persistentClass.SubclassIterator)
{
System.Type subclassProxy = subclass.ProxyInterface;
System.Type subclassClass = subclass.MappedClass;
if (subclassProxy != null &&
!subclassClass.Equals(subclassProxy))
{
if (!subclassProxy.IsInterface)
{
throw new MappingException("proxy must be either an
interface, or the class itself: " + subclass.EntityName);
}
proxyInterfaces.Add(subclassProxy);
}
}
/*
* NH Different Implementation (for Error logging):
* - Check if the logger is enabled
* - Don't need nothing to check if the mapped-class or proxy is
an interface
*/
if (log.IsErrorEnabled && needAccesorCheck)
{
LogPropertyAccessorsErrors(persistentClass);
}
/**********************************************************/
MethodInfo idGetterMethod = idGetter == null ? null :
idGetter.Method;
MethodInfo idSetterMethod = idSetter == null ? null :
idSetter.Method;
MethodInfo proxyGetIdentifierMethod = idGetterMethod == null ||
_proxyInterface == null ? null :
ReflectHelper.TryGetMethod(_proxyInterface, idGetterMethod);
MethodInfo proxySetIdentifierMethod = idSetterMethod == null ||
_proxyInterface == null ? null :
ReflectHelper.TryGetMethod(_proxyInterface, idSetterMethod);
IProxyFactory pf = BuildProxyFactoryInternal(persistentClass,
idGetter, idSetter);
try
{
pf.PostInstantiate(EntityName, _mappedClass,
proxyInterfaces, proxyGetIdentifierMethod, proxySetIdentifierMethod,
persistentClass.HasEmbeddedIdentifier ?
(IAbstractComponentType)persistentClass.Identifier.Type : null);
}
catch (HibernateException he)
{
log.Warn("could not create proxy factory for:" + EntityName,
he);
pf = null;
}
return pf;
}
private void LogPropertyAccessorsErrors(PersistentClass
persistentClass)
{
if (proxyValidator == null)
{
return;
}
// This method work when Environment.UseProxyValidator is off
System.Type clazz = persistentClass.MappedClass;
foreach (Mapping.Property property in
persistentClass.PropertyIterator)
{
MethodInfo method = property.GetGetter(clazz).Method;
if (!proxyValidator.IsProxeable(method))
{
log.Error(
string.Format("Getters of lazy classes cannot be
final: {0}.{1}", persistentClass.MappedClass.FullName,
property.Name));
}
method = property.GetSetter(clazz).Method;
if (!proxyValidator.IsProxeable(method))
{
log.Error(
string.Format("Setters of lazy classes cannot be
final: {0}.{1}", persistentClass.MappedClass.FullName,
property.Name));
}
}
}
protected virtual IProxyFactory
BuildProxyFactoryInternal(PersistentClass @class, IGetter getter, ISetter
setter)
{
return
Cfg.Environment.BytecodeProvider.ProxyFactoryFactory.BuildProxyFactory();
}
public override void AfterInitialize(object entity, bool
lazyPropertiesAreUnfetched, ISessionImplementor session)
{
if (IsInstrumented)
{
HashedSet<string> lazyProps = lazyPropertiesAreUnfetched &&
EntityMetamodel.HasLazyProperties ? lazyPropertyNames : null;
//TODO: if we support multiple fetch groups, we would need
// to clone the set of lazy properties!
FieldInterceptionHelper.InjectFieldInterceptor(entity,
EntityName, lazyProps, session);
}
}
public override object[] GetPropertyValues(object entity)
{
if (ShouldGetAllProperties(entity) && optimizer != null &&
optimizer.AccessOptimizer != null)
{
return GetPropertyValuesWithOptimizer(entity);
}
else
{
return base.GetPropertyValues(entity);
}
}
private object[] GetPropertyValuesWithOptimizer(object entity)
{
return optimizer.AccessOptimizer.GetPropertyValues(entity);
}
public override object[] GetPropertyValuesToInsert(object entity,
System.Collections.IDictionary mergeMap, ISessionImplementor session)
{
if (ShouldGetAllProperties(entity) && optimizer != null &&
optimizer.AccessOptimizer != null)
{
return GetPropertyValuesWithOptimizer(entity);
}
else
{
return base.GetPropertyValuesToInsert(entity, mergeMap,
session);
}
}
public override bool HasUninitializedLazyProperties(object entity)
{
if (EntityMetamodel.HasLazyProperties)
{
IFieldInterceptor callback =
FieldInterceptionHelper.ExtractFieldInterceptor(entity);
return callback != null && !callback.IsInitialized;
}
else
{
return false;
}
}
public override bool IsLifecycleImplementor
{
get { return islifecycleImplementor; }
}
public override void SetPropertyValues(object entity, object[]
values)
{
if (!EntityMetamodel.HasLazyProperties && optimizer != null &&
optimizer.AccessOptimizer != null)
{
SetPropertyValuesWithOptimizer(entity, values);
}
else
{
base.SetPropertyValues(entity, values);
}
}
private void SetPropertyValuesWithOptimizer(object entity, object[]
values)
{
try
{
optimizer.AccessOptimizer.SetPropertyValues(entity, values);
}
catch (InvalidCastException e)
{
throw new PropertyAccessException(e, "Invalid Cast (check
your mapping for property type mismatches);", true,
entity.GetType());
}
}
public override bool IsValidatableImplementor
{
get { return isValidatableImplementor; }
}
public override EntityMode EntityMode
{
get { return EntityMode.Poco; }
}
}
[Serializable]
public class IocInstantiator : IInstantiator, IDeserializationCallback
{
private static readonly ILog log =
LogManager.GetLogger(typeof(PocoInstantiator));
[NonSerialized]
private readonly IInstantiationOptimizer optimizer;
private readonly bool embeddedIdentifier;
private readonly Type mappedClass;
private readonly Type proxyInterface;
[NonSerialized]
private ConstructorInfo constructor;
public IocInstantiator()
{
}
public IocInstantiator(Component component, IInstantiationOptimizer
optimizer)
{
mappedClass = component.ComponentClass;
this.optimizer = optimizer;
proxyInterface = null;
embeddedIdentifier = false;
if (IoC.IsInitialized &&
IoC.Container.Kernel.HasComponent(mappedClass))
constructor = null;
else
{
try
{
constructor =
ReflectHelper.GetDefaultConstructor(mappedClass);
}
catch (PropertyNotFoundException)
{
log.Info(string.Format("no default (no-argument)
constructor for class: {0} (class must be instantiated by Interceptor)",
mappedClass.FullName));
constructor = null;
}
}
}
public IocInstantiator(PersistentClass persistentClass,
IInstantiationOptimizer optimizer)
{
mappedClass = persistentClass.MappedClass;
proxyInterface = persistentClass.ProxyInterface;
embeddedIdentifier = persistentClass.HasEmbeddedIdentifier;
this.optimizer = optimizer;
if (IoC.IsInitialized &&
IoC.Container.Kernel.HasComponent(mappedClass))
constructor = null;
else
{
try
{
constructor =
ReflectHelper.GetDefaultConstructor(mappedClass);
}
catch (PropertyNotFoundException)
{
log.Info(string.Format("no default (no-argument)
constructor for class: {0} (class must be instantiated by Interceptor)",
mappedClass.FullName));
constructor = null;
}
}
}
#region IInstantiator Members
public object Instantiate(object id)
{
bool useEmbeddedIdentifierInstanceAsEntity = embeddedIdentifier
&& id != null && id.GetType().Equals(mappedClass);
return useEmbeddedIdentifierInstanceAsEntity ? id :
Instantiate();
}
public object Instantiate()
{
if (ReflectHelper.IsAbstractClass(mappedClass))
{
throw new InstantiationException("Cannot instantiate
abstract class or interface: ", mappedClass);
}
else if (optimizer != null)
{
return optimizer.CreateInstance();
}
else if (mappedClass.IsValueType)
{
return Activator.CreateInstance(mappedClass, true);
}
else if (constructor == null)
{
var instance = IoC.IsInitialized ? IoC.Resolve(mappedClass)
: null;
if (instance != null) return instance;
throw new InstantiationException("No default constructor for
entity: ", mappedClass);
}
else
{
try
{
return constructor.Invoke(null);
}
catch (Exception e)
{
throw new InstantiationException("Could not instantiate
entity: ", e, mappedClass);
}
}
}
public bool IsInstance(object obj)
{
return mappedClass.IsInstanceOfType(obj) || (proxyInterface !=
null && proxyInterface.IsInstanceOfType(obj)); //this one needed only for
guessEntityMode()
}
#endregion
#region IDeserializationCallback Members
public void OnDeserialization(object sender)
{
constructor = ReflectHelper.GetDefaultConstructor(mappedClass);
}
#endregion
}
2008/11/20 Fabio Maulo <[EMAIL PROTECTED]>
> 2008/11/19 Lee Henson <[EMAIL PROTECTED]>
>
>> Do I need to code for optimizers etc?
>>
>
> Hi Lee.
> I don't know what you need.
> --
> Fabio Maulo
>
> >
>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en
-~----------~----~----~----~------~----~------~--~---