-
Notifications
You must be signed in to change notification settings - Fork 934
GH-1881 - Fix interface method attributes when generating proxies #1882
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
Conversation
This comment has been minimized.
This comment has been minimized.
Added the necessary test. |
This comment has been minimized.
This comment has been minimized.
[Test] | ||
public void InterfacesShouldBeImplementedExplicitlyOnProxies() | ||
{ | ||
var proxy = new ProxyFactory().CreateProxy(typeof(PersistentGenericBag<object>), null, typeof(ILazyInitializedCollection)); |
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.
Adding a test:
[Test]
public void PassProxyValidation()
{
var validator = new DynProxyTypeValidator();
Assert.That(validator.ValidateType(typeof(PersistentGenericBag<object>)), Is.Null.Or.Count.EqualTo(0));
}
Shows that PersistentGenericBag<object>
does not fulfil prerequisites for being a proxy, with a long list of errors. This may cause the test to fail for unrelated reasons with future changes. This test should use a custom class instead.
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.
Well... no, but that's kind of the point.
To reproduce the issue I would need a type that isn't validatable.
public interface IFoo
{
bool Prop { get; }
}
public class Bar : IFoo
{
public bool Prop => false;
}
// throws the same error
new ProxyFactory().CreateProxy(typeof(Bar), null, typeof(IFoo));
The proxy factory generates a proxy type for Bar
, skipping Prop
because it isn't proxyable.
But it adds the property from IFoo
, which is proxyable, which is wrong and causes errors.
With the explicit implementation of the interface the proxy is valid for the interface, if not for the base type.
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.
It would be still better to use this type for the test than this big thing that PersistentGenericBag
is.
So, there are actually no ways to reproduce the failure when using the dynamic proxy factory only through NHibernate's proxy handling, isn't it? (Or does Envers disable the default proxy validation in NHibernate? There is a setting allowing this.)
So this change looks needed for somewhat external users of the dynamic proxy factory, using it for their own needs with less strict prerequisites on proxied classes. But that is not the purpose of NHibernate to provide a general purpose proxifying mechanism. In this spirit the new static proxy factory API is way less exposed (more internal), and the old dynamic proxy should be gone in 6.0.
Maybe Envers will need to use an external proxy library rather than using the NHibernate internal one. (Unless it can be changed to use the static proxy factory, if it is not too specific to NHibernate for being used for Envers case. But I doubt about this.)
(In other words, this all looks to me at lot like this other discussion.)
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.
In the example above Bar
will fail the validation.
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.
Or does Envers disable the default proxy validation in NHibernate? There is a setting allowing this.
They use it for something different - as a general purpose proxy factory to inject an interceptor, not for nhibernate entities.
public class TestFixture | ||
{ | ||
[Test] | ||
public void InterfacesShouldBeImplementedExplicitlyOnProxies() |
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.
A static proxy test should also be added, since the dynamic proxy is to be dropped.
Example code for reproducing the issue with static proxy:
var factory = new StaticProxyFactory();
factory.PostInstantiate("PersistentGenericBag<object>", typeof(PersistentGenericBag<object>),
new HashSet<System.Type> {typeof(ILazyInitializedCollection)}, null, null, null);
var proxy = factory.GetProxy(1, null);
Of course, a custom class should be used here too, for avoiding troubles due to PersistentGenericBag<object>
being not meant to comply with proxification prerequisites.
The static test could be added in NHibernate.Test.StaticProxyTest.StaticProxyFactoryFixture
, since NHSpecificTest
is for things which do not really have a suitable feature test fixture. (Dynamic proxy test folder does not seem to contain a suitable fixture currently for the test here.)
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.
I added the test and it fails
NHibernate.HibernateException : Creating a proxy instance failed
----> System.ArgumentException : Expression of type 'PersistentGenericBag`1Proxy' cannot be used for return type 'NHibernate.Proxy.INHibernateProxy'
at NHibernate.Proxy.StaticProxyFactory.GetProxy(Object id, ISessionImplementor session) in D:\ExternalGit\nhibernate-core-pleasantd\src\NHibernate\Proxy\StaticProxyFactory.cs:line 31
at NHibernate.Test.StaticProxyTest.StaticProxyFactoryFixture.VerifyInterfacesImplementedExplicitlyOnProxies() in D:\ExternalGit\nhibernate-core-pleasantd\src\NHibernate.Test\StaticProxyTest\StaticProxyFactoryFixture.cs:line 153
--ArgumentException
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters, String paramName)
at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 parameters)
at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, ParameterExpression[] parameters)
at NHibernate.Proxy.StaticProxyFactory.CreateProxyActivator(ProxyCacheEntry pke) in D:\ExternalGit\nhibernate-core-pleasantd\src\NHibernate\Proxy\StaticProxyFactory.cs:line 42
at NHibernate.Proxy.StaticProxyFactory.<GetProxy>b__3_0(ProxyCacheEntry pke) in D:\ExternalGit\nhibernate-core-pleasantd\src\NHibernate\Proxy\StaticProxyFactory.cs:line 23
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at NHibernate.Proxy.StaticProxyFactory.GetProxy(Object id, ISessionImplementor session) in D:\ExternalGit\nhibernate-core-pleasantd\src\NHibernate\Proxy\StaticProxyFactory.cs:line 23
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.
Yes, that should be new HashSet<System.Type> { typeof(INHibernateProxy) }
instead.
But well, as per the comment I have posted some seconds ago here, it is maybe useless to support this in the static proxy factory, which is way less a general purpose proxifying mechanism than the dynamic proxy, and which may be unsuitable for Envers needs.
Update: it should only include INHibernateProxy
, otherwise it will use the second interface as the base for the implementation. The ILazyInitializedCollection
will be added by inspection of the base type.
…ating proxies Fix a broken test
This comment has been minimized.
This comment has been minimized.
I suppose as an alternative we could just patch Envers is generating this error because it generates proxies of the collections so it can hook into If we add the
|
Agree
…On Wed, 24 Oct 2018 at 10:47, Duncan Munro ***@***.***> wrote:
I suppose as an alternative we could just fix AbstractPersistentCollection
.
Envers is generating this error because it generates proxies of the
collections so it can hook into ILazyInitializedCollection.
AbstractPersistentCollection implements ILazyInitializedCollection but
doesn't implement WasInitialized as virtual.
If we add the virtual keyword then it should fix Envers' issue with
creating proxies of collections.
https://github.com/nhibernate/nhibernate-core/blob/5c184527752b6e1fe7d40e91536dfdae300e287c/src/NHibernate/Collection/AbstractPersistentCollection.cs#L633
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1882 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAI1l3XgCURm2-fSLUf5BxWY6XdFtEG8ks5un45ogaJpZM4Xxhs9>
.
|
How would you like to proceed with this? Please let me know what needs to be done to fix this up or if you'd rather just patch |
It seems patching |
…ating proxies Rmove some undue changes
…ating proxies Simplify broken test fix
MethodAttributes.NewSlot | | ||
MethodAttributes.SpecialName; | ||
// .NET uses an expanded name for explicit interface implementation methods. | ||
name = typeBuilder.FullName + "." + method.DeclaringType.FullName + "." + name; |
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.
This is not what .NET have for methods.
Looking into it, there are many more properties in So, proxified by the dynamic proxy, it may not trigger the issue. But would a proxy of So implementing |
For the same reason than #1881, closing.
|
See #1881