blackdrag commented on PR #3086:
URL: https://github.com/apache/groovy/pull/3086#issuecomment-6750516676
Hibernate proxy rules as I understand what has to be there to support lazy
init:
1. method must be not private, final or static.
2. fields are not supported using the subclass proxy.
3. supporting package private and protected methods requires same package
and class loader (and module), which requires ByteBuddy for example to go to
quite some lengths to support that properly, including exposing a LookupObject
that has full access to the entity.
4. interface default methods may or may not be in the proxy, depending on
settings. Technically they do not exist on the entity
5. constructor is not on the proxy
6. proxy will contain additional methods to support the interfaces it
implements, which excludes them from the entity as possible method names
7. equals (and hashcode) may require special handling.
8. inherited parent methods for entity may call methods from entity
In case of inheritance in Java we have these rules for the proxy
1. cannot be overwritten, private methods are not really inherited, but
also not visible outside. Proxy does not contain them
2. fields are inherited, if not private, but they break lazy init in the
hibernate proxy. Proxy does not contain them.
3. package private and protected methods are visible in the proxy, if in the
same package and class loader. Proxy must contain them.
4. Proxy may contain them
5. no entity constructor on the proxy
6. obviously the proxy will contain them, but that restricts available
method names in the entity
7. assume I have a check `other.getClass() == MyEntity.class`, then a proxy
in `other` would break.
8. need to create proxy methods for them. the field restriction also applies
to parent classes
What happens if we use such a proxy in Groovy? Because the proxy is a Groovy
class it will proxy getMetaClass and deliver the entity meta class instead of
the proxy metaclass.
What would happen if metaClass(proxy) is the meta class for the proxy class?
In that case we would see something similar to what Java sees, so all should be
fine within the Java rules.
If entity has no normal meta class, or for example EMC with a method added?
Then the meta class of proxy may not see that.
If the proxy uses the meta class of the entity it does proxy, then you would
see methods added through runtime meta programming to entity also on proxy. It
would not see additional methods on proxy, it would claim to have private
methods and fields on proxy, that are not on proxy. It would report the
constructors of entity, not the ones from proxy. A static method of the same
name on proxy would be called instead of entity if used like an instance
method.
Which reminds me of a chapter I should open here as well... that is
closures. A closure in the entity would operate on the proxy instance. If that
closure tries to call a private method/field on entity it my fail because it
actually works on proxy but thinks it operates on entity.
```Groovy
class X {
private foo() {"foo X"}
public bar() {def cl = {foo()}; cl()}
}
assert new X().bar() == "foo X"
class Y extends X {
private foo() {"foo Y"}
}
assert new Y().bar() == "foo Y"
def y = new Y()
def x = new X()
y.metaClass = x.metaClass
assert y.bar() == "foo X" // <-- changed because of wrong meta class
class Z extends X{}
def z = new Z()
assert z.bar() == "foo X" // may fail in Groovy 4
z.metaClass = x.metaClass
assert z.bar() == "foo X" // <-- correct even though wrong meta class,
because Z has no foo()
```
And of course traits:
```
trait MyTrait {
private secret() {"secret"}
String state = "state from trait "
String bar() { foo() + this.class.name + " " + secret() + " " +
this.metaClass.theClass.name}
def foo(){};
}
class X implements MyTrait{
def foo() {state}
}
assert new X().bar() == "state from trait X secret X"
class Y extends X {
def foo() {"foo Y "}
}
assert new Y().bar() == "foo Y Y secret Y"
def y = new Y()
def x = new X()
y.metaClass = x.metaClass
assert y.bar() == "foo Y Y secret X"
class Z extends X{}
def z = new Z()
assert z.bar() == "state from trait Z secret Z"
z.metaClass = x.metaClass
assert z.bar() == "state from trait Z secret X"
```
which does not proof something breaks right away, but of course the instance
metaclass leaks into the trait.
Of course with @POJO the situation would look very different again.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]