-
Notifications
You must be signed in to change notification settings - Fork 933
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
Changes from all commits
53154a7
27deceb
2000843
402f14c
5c87d9a
61ed84f
783c575
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 |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Reflection; | ||
using NHibernate.Collection; | ||
using NHibernate.Collection.Generic; | ||
using NHibernate.Proxy.DynamicProxy; | ||
using NUnit.Framework; | ||
|
||
namespace NHibernate.Test.NHSpecificTest.GH1881 | ||
{ | ||
[TestFixture] | ||
[Obsolete] | ||
public class TestFixture | ||
{ | ||
[Test] | ||
public void InterfacesShouldBeImplementedExplicitlyOnProxies() | ||
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. 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 The static test could be added in 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. I added the test and it fails
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. Yes, that should be 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 |
||
{ | ||
var proxy = new ProxyFactory().CreateProxy(typeof(PersistentGenericBag<object>), null, typeof(ILazyInitializedCollection)); | ||
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. 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 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. Well... no, but that's kind of the point.
The proxy factory generates a proxy type for 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. It would be still better to use this type for the test than this big thing that 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 commentThe reason will be displayed to describe this comment to others. Learn more. In the example above 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.
They use it for something different - as a general purpose proxy factory to inject an interceptor, not for nhibernate entities. |
||
Assert.That(proxy, Is.Not.Null); | ||
|
||
foreach (var method in proxy.GetType().GetMethods().Where(m => m.DeclaringType == typeof(ILazyInitializedCollection))) | ||
{ | ||
// These attributes are what .NET uses for explicitly implemented interface methods | ||
Assert.That(method.Attributes, Is.EqualTo(MethodAttributes.Private | | ||
MethodAttributes.Final | | ||
MethodAttributes.Virtual | | ||
MethodAttributes.HideBySig | | ||
MethodAttributes.NewSlot | | ||
MethodAttributes.SpecialName)); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -137,7 +137,24 @@ internal static MethodBuilder GetObjectDataMethodBuilder(TypeBuilder typeBuilder | |
internal static MethodBuilder GenerateMethodSignature(string name, MethodInfo method, TypeBuilder typeBuilder) | ||
{ | ||
//TODO: Should we use attributes of base method? | ||
var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; | ||
MethodAttributes methodAttributes; | ||
if (method.DeclaringType.IsInterface) | ||
{ | ||
// These are the attributes used for an explicit interface method implementation in .NET. | ||
methodAttributes = | ||
MethodAttributes.Private | | ||
MethodAttributes.Final | | ||
MethodAttributes.Virtual | | ||
MethodAttributes.HideBySig | | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. This is not what .NET have for methods. |
||
} | ||
else | ||
{ | ||
methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; | ||
} | ||
|
||
if (method.IsSpecialName) | ||
methodAttributes |= MethodAttributes.SpecialName; | ||
|
Uh oh!
There was an error while loading. Please reload this page.