# @Proxy deprecated in Hibernate 6.2

**URL:** <https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707>\
**Category:** Hibernate ORM\
**Created:** [May 29, 2023, 8:24am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707 "2023-05-29T08:24:01Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![gtoison](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/gtoison/32/3069_2.png) [@gtoison](https://discourse.hibernate.org/u/gtoison)\
**Post date:** [May 29, 2023, 8:24am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/1 "2023-05-29T08:24:01Z")

</div>

Hello,

Since Hibernate 6.2 the `@Proxy` annotation is deprecated with the comment: `This annotation is almost never useful.`

I have a rather large domain model on Hibernate 5.5 where one particular entity has many subclasses (and some have themselves subclasses) mapped with `@Inheritance(strategy = InheritanceType.SINGLE_TABLE)`  
This is a bit like: `Wolf extends Mammal extends Vertebrate extends Animal`  
and: `Snail extends Mollusk extends Animal`

Now when I have loaded these objects I often get uninitialized proxies (which is fine) but these proxies are instances of `Animal` but I’d like to get instances of the relevant class i.e., `Wolf` or `Snail` because if want to be able to write things like:

```auto
if (animal instanceof Snail snail) {
   return snail.getShell();
} else {
   return null;
}

```

I understand why Hibernate creates a proxy instance of `Animal` (for instance when there’s a `@ManyToOne` association typed as `Animal`) and I also get that I could declare an abstract `getShell()` method on my `Animal` class, but to get around this problem I have annotated the class with `@Proxy(lazy = false)`.  
Doing that I lose some lazy loading, but I end up with a saner design.

To be clear, the idea here is not to get around a `LazyInitializationException` by disabling proxies: what I need is to get a an object (possibly a proxy) of the correct class.

When trying to upgrade from 5.5 to 6.2 I’m running into two issues that both disappear when removing the `@Proxy(lazy = false)` annotations:

> [@ObjectNotFoundException in 6.2 when reusing a column](https://discourse.hibernate.org/t/objectnotfoundexception-in-6-2-when-reusing-a-column/7636/3):
>
> You’re right, I’ve removed some code for brevity but got the annotation wrong: indeed I am using @JoinColumn and @ManyToOne If this seems like a bug I’ll try to put together a test case reproducing the problem Thanks!

> [@StackOverflowError in 6.2 with @Proxy(lazy = false)](https://discourse.hibernate.org/t/stackoverflowerror-in-6-2-with-proxy-lazy-false/7594/6):
>
> Thanks Christian, when you have time to have a look at the failing test case I’ve submitted, could you please let me know if you feel that it’s a genuine issue in Hibernate or if I’m misusing it?

So I’m wondering what the Hibernate team has planned: is the intent to drop the support for `@Proxy(lazy = false)` down the road?  
If so, is there a replacement planned to support the case when you need the objects to be of the correct class?

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [May 30, 2023, 7:58am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/2 "2023-05-30T07:58:06Z")

</div>

I think that `@Proxy(lazy = false)` so far only resulted in making every association that refers to that type implicitly `EAGER` to avoid the problem of creating proxies of the “wrong type”, but that hurts performance.

I think that one possible solution to this problem could be to add the discriminator to the association side, next to the FK column, but that’s a new feature and will take a while, though I think that would be a good replacement.

One simple way to get around this would be to add a method to your top type:

```java
boolean isInstance(Class<?> clazz) {
    return clazz.isInstance(this);
}

```

This will trigger lazy initialization if necessary, but is still easy to use.

---

<div class="post-metadata">

**Author:** ![gtoison](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/gtoison/32/3069_2.png) [@gtoison](https://discourse.hibernate.org/u/gtoison)\
**Post date:** [May 30, 2023, 9:30am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/3 "2023-05-30T09:30:07Z")

</div>

Thanks for the answer,  
I agree that `@Proxy(lazy = false)` carries a performance penalty due to the eager fetching.

The proposed solution to add a discriminator next to the FK column sounds good, alternatively could the discriminator be part of the ID itself?

Another solution would be for Hibernate to let the user plug some kind of resolver that, given an ID, returns the correct type.

Something like:

```auto
public interface CustomEntityTypeResolver {
	Class<?> resolveClass(Serializable id);
}

```

Also, the entity might be in the second-level cache. In my testing the correct type is returned when that happens, so it might be a workable solution.

The `class.isInstance(...)` test does not seem to work unfortunately, because the object is of class `Animal$HibernateProxy$xyz`, so both these tests are false:

- `Snail.class.isInstance(animal)`
- `animal instanceof Snail`

The reliable method I have found is to use:  
`Hibernate.isInstance(animal, Snail.class);`  
and:  
`Snail snail = (Snail) Hibernate.unproxy(animal);`

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [May 30, 2023, 10:16am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/4 "2023-05-30T10:16:31Z")

</div>

> The proposed solution to add a discriminator next to the FK column sounds good, alternatively could the discriminator be part of the ID itself?

You can map the discriminator as part of an embedded id, but this information will not be used for proxies yet.

> Another solution would be for Hibernate to let the user plug some kind of resolver that, given an ID, returns the correct type.

That is certainly an option, but how would you determine the type based on the id?

> Also, the entity might be in the second-level cache. In my testing the correct type is returned when that happens, so it might be a workable solution.

The thing is, you usually can’t rely on this.

> The `class.isInstance(...)` test does not seem to work unfortunately, because the object is of class `Animal$HibernateProxy$xyz` , so both these tests are false

Every method call to a proxy except for the `getId` method should delegate to the implementation and hence initialize the proxy. Can you show me what fails? The code responsible for this should be `org.hibernate.proxy.pojo.BasicLazyInitializer#invoke`

---

<div class="post-metadata">

**Author:** ![gtoison](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/gtoison/32/3069_2.png) [@gtoison](https://discourse.hibernate.org/u/gtoison)\
**Post date:** [May 30, 2023, 11:54am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/5 "2023-05-30T11:54:14Z")

</div>

> > Another solution would be for Hibernate to let the user plug some kind of resolver that, given an ID, returns the correct type.
> 
> That is certainly an option, but how would you determine the type based on the id?

I’m thinking of an application-level service initialized at startup and kept up-to-date whenever a new entity is created.  
In my case theses entities are not created often and there are not so many, so essentially I could implement this by:

- Initializing an ID/class map at startup with an SQL query and then locating the java class from the discriminator using the metamodel
- Whenever a new entity is created, add the class to the map
- In case (wouldn’t happen in my case) there’s entry for an ID, throw an exception or possibly run a separate SQL query

> > The `class.isInstance(...)` test does not seem to work unfortunately, because the object is of class `Animal$HibernateProxy$xyz` , so both these tests are false
> 
> Every method call to a proxy except for the `getId` method should delegate to the implementation and hence initialize the proxy. Can you show me what fails? The code responsible for this should be `org.hibernate.proxy.pojo.BasicLazyInitializer#invoke`

Sorry, I did not get that your suggestion was an instance method. Indeed this is delegated to the implementation and returns the correct class 👍

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [May 31, 2023, 7:10am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/6 "2023-05-31T07:10:14Z")

</div>

> I’m thinking of an application-level service initialized at startup and kept up-to-date whenever a new entity is created.  
> In my case theses entities are not created often and there are not so many, so essentially I could implement this by:

Instead of doing this yourself, you could just activate the second level cache for that entity then, which should result in more or less the same behavior 😉

---

<div class="post-metadata">

**Author:** ![gtoison](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/gtoison/32/3069_2.png) [@gtoison](https://discourse.hibernate.org/u/gtoison)\
**Post date:** [May 31, 2023, 10:41am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/7 "2023-05-31T10:41:00Z")

</div>

Yes, putting the entity in the 2nd level cache would be a good solution!

Now, what would it entail to get this hypothetical `CustomEntityTypeResolver` added to the Hibernate API?  
I only know Hibernate well enough to be dangerous but I can offer to contribute 🙂 however I’m not sure how high would be the bar for that kind of enhancement.  
I suppose that this kind of change would need to be discussed internally in the Hibernate team.

Let me know if there’s anything I can do to get the ball rolling!

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [May 31, 2023, 10:49am UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/8 "2023-05-31T10:49:51Z")

</div>

I don’t think that `CustomEntityTypeResolver` would be a good solution. Allowing the discriminator to be part of the FK side makes much more sense IMO.

The best way to start contributing if you want to do that, would be to create a JIRA issue. Next step would be to discussing this on Zulip with the rest of the team and help us write tests that assert the intended behavior. When we have that, we can prototype an implementation.

---

<div class="post-metadata">

**Author:** ![Samuel\_Beausoleil](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/samuel_beausoleil/32/3057_2.png) [@Samuel\_Beausoleil](https://discourse.hibernate.org/u/Samuel_Beausoleil)\
**Post date:** [February 28, 2024, 4:30pm UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/9 "2024-02-28T16:30:04Z")

</div>

Unrelated to the question but to the title: @Proxy(lazy = false) is the only way to have sealed classes as entities. If that annotation is removed that would mean losing support for that type of class.

---

<div class="post-metadata">

**Author:** ![beikov](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/beikov/32/258_2.png) [@beikov](https://discourse.hibernate.org/u/beikov)\
**Post date:** [March 6, 2024, 5:18pm UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/10 "2024-03-06T17:18:06Z")

</div>

Don’t worry about this, we’re going to add a replacement for this [[HHH-17818] - Hibernate JIRA](https://hibernate.atlassian.net/browse/HHH-17818)

---

<div class="post-metadata">

**Author:** ![gtoison](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/gtoison/32/3069_2.png) [@gtoison](https://discourse.hibernate.org/u/gtoison)\
**Post date:** [March 6, 2024, 5:47pm UTC](https://discourse.hibernate.org/t/proxy-deprecated-in-hibernate-6-2/7707/11 "2024-03-06T17:47:42Z")

</div>

This is great news, thank you very much for improving this (instead of removing it)!
