Firstly, two rules:
- The proxy server delegates all non-final method calls to the target instance, with the exception of the method to get the identifier if the mappings specify access to the resource for id.
- Proxy objects are never initialized; the target instance is initialized.
1) Suppose you call a.equals(b) , where both a and b are proxies of the same object. And let's say that the equals method is implemented as follows:
public boolean equals(Object other) { ... if (this.someField.equals(other.someField)) { ... } ... }
The equals a method is delegated to the target instance, causing it to be fully initialized. Thus, you are not safe with the fields in instance a (you can use them directly).
However, accessing fields directly in instance b ( other.someField ) never matches. It does not matter if b initialized or not, the proxy instance is never initialized, but only the target instance. So, someField always null in instance b .
The correct implementation is to use getters for at least the other instance:
this.someField.equals(other.getSomeField())
or be consistent:
this.getSomeField().equals(other.getSomeField())
In final methods, everything is different: Hibernate cannot override them to delegate a call to the target. So, if the equals method was final in the previous example, you will get a NullPointerException when accessing this.someField .
All this can be avoided by configuring Hibernate to use bytecode tools instead of proxies, but it has its own errors and is not widely accepted.
2) Again, it never initializes the proxy instance itself. When it comes to initializing the target instance, it depends on whether the field or access to properties in the mappings is determined. In both cases, reflection is used (to assign values ββdirectly to fields in case of access to the field or to call setters in case of access to properties).
Dragan bozanovic
source share