Class ManagedTypeHelper
- java.lang.Object
-
- org.hibernate.engine.internal.ManagedTypeHelper
-
public final class ManagedTypeHelper extends Object
This is a helper to encapsulate an optimal strategy to execute type checks for interfaces which attempts to avoid the performance issues tracked as JDK-8180450; the problem is complex and explained better on the OpenJDK tracker; we'll focus on a possible solution here.To avoid polluting the secondary super-type cache, the important aspect is to not switch types repeatedly for the same concrete object; using a Java agent which was developed for this purpose (https://github.com/franz1981/type-pollution-agent) we identified a strong case with Hibernate ORM is triggered when the entities are using bytecode enhancement, as they are being frequently checked for compatibility with the following interfaces:
Some additional interfaces are involved in bytecode enhancement (such as
ManagedMappedSuperclass
), but some might not be managed here as there was no evidence of them triggering the problem; this might change after further testing.The approach we pursue is to have all these internal interfaces extend a single interface
PrimeAmongSecondarySupertypes
which then exposes a type widening contract; this allows to consistently cast toPrimeAmongSecondarySupertypes
exclusively and avoid any further type checks; since the cast consistently happens on this interface we avoid polluting the secondary super type cache described in JDK-8180450.This presents two known drawbacks:
1# we do assume such user entities aren't being used via interfaces in hot user code; this is typically not the case based on our experience of Hibernate usage, but it can't be ruled out.
2# we're introducing virtual dispatch calls which are likely going to be megamorphic; this is not great but we assume it's far better to avoid the scalability issue.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interface
ManagedTypeHelper.PersistentAttributeInterceptableAction<T>
This interface has been introduced to mitigate JDK-8180450.
Sadly, usingBiConsumer
will trigger a type pollution issue because of generics type-erasure:BiConsumer
's actual parameters types on the lambda implemention'sBiConsumer.accept(T, U)
are stealthy enforced viacheckcast
, messing up with type check cached data.static interface
ManagedTypeHelper.SelfDirtinessTrackerAction<T>
static interface
ManagedTypeHelper.SelfDirtinessTrackerConsumer
-
Constructor Summary
Constructors Constructor Description ManagedTypeHelper()
-
Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static CompositeOwner
asCompositeOwner(Object entity)
Cast the object to CompositeOwner (using this is highly preferrable over a direct cast)static CompositeTracker
asCompositeTracker(Object entity)
Cast the object to CompositeTracker (using this is highly preferrable over a direct cast)static HibernateProxy
asHibernateProxy(Object entity)
Cast the object to HibernateProxy (using this is highly preferrable over a direct cast)static HibernateProxy
asHibernateProxyOrNull(Object entity)
Cast the object to an HibernateProxy, or return null in case it is not an instance of HibernateProxystatic ManagedEntity
asManagedEntity(Object entity)
Cast the object to ManagedEntity (using this is highly preferrable over a direct cast)static PersistentAttributeInterceptable
asPersistentAttributeInterceptable(Object entity)
Cast the object to PersistentAttributeInterceptable (using this is highly preferrable over a direct cast)static PersistentAttributeInterceptable
asPersistentAttributeInterceptableOrNull(Object entity)
static SelfDirtinessTracker
asSelfDirtinessTracker(Object entity)
Cast the object to SelfDirtinessTracker (using this is highly preferrable over a direct cast)static boolean
isCompositeOwner(Object entity)
static boolean
isCompositeTracker(Object entity)
static boolean
isHibernateProxy(Object entity)
static boolean
isManagedEntity(Object entity)
static boolean
isManagedType(Class type)
static boolean
isPersistentAttributeInterceptable(Object entity)
static boolean
isPersistentAttributeInterceptableType(Class type)
static boolean
isSelfDirtinessTracker(Object entity)
static boolean
isSelfDirtinessTrackerType(Class type)
static <T> void
processIfPersistentAttributeInterceptable(Object entity, ManagedTypeHelper.PersistentAttributeInterceptableAction<T> action, T optionalParam)
Helper to execute an action on an entity, but exclusively if it's implementing the {@see PersistentAttributeInterceptable} interface.static <T> void
processIfSelfDirtinessTracker(Object entity, ManagedTypeHelper.SelfDirtinessTrackerAction<T> action, T optionalParam)
If the entity is implementing SelfDirtinessTracker, apply some action to it; this action should take a parameter of type T.static void
processIfSelfDirtinessTracker(Object entity, ManagedTypeHelper.SelfDirtinessTrackerConsumer action)
If the entity is implementing SelfDirtinessTracker, apply some action to it.
-
-
-
Method Detail
-
isManagedType
public static boolean isManagedType(Class type)
- Parameters:
type
-- Returns:
- true if and only if the type is assignable to a {@see Managed} type.
-
isSelfDirtinessTrackerType
public static boolean isSelfDirtinessTrackerType(Class type)
- Parameters:
type
-- Returns:
- true if and only if the type is assignable to a {@see SelfDirtinessTracker} type.
-
isPersistentAttributeInterceptableType
public static boolean isPersistentAttributeInterceptableType(Class type)
- Parameters:
type
-- Returns:
- true if and only if the type is assignable to a {@see PersistentAttributeInterceptable} type.
-
isManagedEntity
public static boolean isManagedEntity(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see ManagedEntity}
-
isHibernateProxy
public static boolean isHibernateProxy(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see HibernateProxy}
-
isPersistentAttributeInterceptable
public static boolean isPersistentAttributeInterceptable(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see PersistentAttributeInterceptable}
-
isSelfDirtinessTracker
public static boolean isSelfDirtinessTracker(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see SelfDirtinessTracker}
-
isCompositeOwner
public static boolean isCompositeOwner(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see CompositeOwner}
-
isCompositeTracker
public static boolean isCompositeTracker(Object entity)
- Parameters:
entity
-- Returns:
- true if and only if the entity implements {@see CompositeTracker}
-
processIfPersistentAttributeInterceptable
public static <T> void processIfPersistentAttributeInterceptable(Object entity, ManagedTypeHelper.PersistentAttributeInterceptableAction<T> action, T optionalParam)
Helper to execute an action on an entity, but exclusively if it's implementing the {@see PersistentAttributeInterceptable} interface. Otherwise no action is performed.- Type Parameters:
T
- the type of the additional parameter.- Parameters:
entity
-action
- The action to be performed; it should take the entity as first parameter, and an additional parameter T as second parameter.optionalParam
- a parameter which can be passed to the action
-
processIfSelfDirtinessTracker
public static void processIfSelfDirtinessTracker(Object entity, ManagedTypeHelper.SelfDirtinessTrackerConsumer action)
If the entity is implementing SelfDirtinessTracker, apply some action to it. It is first cast to SelfDirtinessTracker using an optimal strategy. If the entity does not implement SelfDirtinessTracker, no operation is performed.- Parameters:
entity
-action
-
-
processIfSelfDirtinessTracker
public static <T> void processIfSelfDirtinessTracker(Object entity, ManagedTypeHelper.SelfDirtinessTrackerAction<T> action, T optionalParam)
If the entity is implementing SelfDirtinessTracker, apply some action to it; this action should take a parameter of type T. It is first cast to SelfDirtinessTracker using an optimal strategy. If the entity does not implement SelfDirtinessTracker, no operation is performed.- Type Parameters:
T
- the type of the additional parameter.- Parameters:
entity
-action
-optionalParam
- a parameter which can be passed to the action
-
asPersistentAttributeInterceptable
public static PersistentAttributeInterceptable asPersistentAttributeInterceptable(Object entity)
Cast the object to PersistentAttributeInterceptable (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asPersistentAttributeInterceptableOrNull
public static PersistentAttributeInterceptable asPersistentAttributeInterceptableOrNull(Object entity)
-
asHibernateProxy
public static HibernateProxy asHibernateProxy(Object entity)
Cast the object to HibernateProxy (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asManagedEntity
public static ManagedEntity asManagedEntity(Object entity)
Cast the object to ManagedEntity (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asCompositeTracker
public static CompositeTracker asCompositeTracker(Object entity)
Cast the object to CompositeTracker (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asCompositeOwner
public static CompositeOwner asCompositeOwner(Object entity)
Cast the object to CompositeOwner (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asSelfDirtinessTracker
public static SelfDirtinessTracker asSelfDirtinessTracker(Object entity)
Cast the object to SelfDirtinessTracker (using this is highly preferrable over a direct cast)- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting
- Throws:
ClassCastException
- if it's not of the right type
-
asHibernateProxyOrNull
public static HibernateProxy asHibernateProxyOrNull(Object entity)
Cast the object to an HibernateProxy, or return null in case it is not an instance of HibernateProxy- Parameters:
entity
- the entity to cast- Returns:
- the same instance after casting or null if it is not an instance of HibernateProxy
-
-