Class 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 to PrimeAmongSecondarySupertypes 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.

    • Constructor Detail

      • ManagedTypeHelper

        public ManagedTypeHelper()
    • 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​(@Nullable 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
      • 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