All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.bytecode.internal.bytebuddy;

import static org.hibernate.internal.CoreLogging.messageLogger;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.hibernate.HibernateException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.TypeCache;
import net.bytebuddy.dynamic.loading.ClassInjector;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.TypeValidation;

/**
 * An utility to hold all ByteBuddy related state, as in the current version of
 * Hibernate the Bytecode Provider state is held in a static field, yet ByteBuddy
 * is able to benefit from some caching and general state reuse.
 */
public final class ByteBuddyState {

	private static final CoreMessageLogger LOG = messageLogger( ByteBuddyProxyFactory.class );

	/**
	 * Ideally shouldn't be static but it has to until we can remove the
	 * deprecated static methods.
	 */
	private static final ByteBuddy buddy = new ByteBuddy().with( TypeValidation.DISABLED );

	/**
	 * This currently needs to be static: the BytecodeProvider is a static field of Environment and
	 * is being accessed from static methods.
	 * It will be easier to maintain the cache and its state when it will no longer be static
	 * in Hibernate ORM 6+.
	 * Opted for WEAK keys to avoid leaking the classloader in case the SessionFactory isn't closed.
	 * Avoiding Soft keys as they are prone to cause issues with unstable performance.
	 */
	private static final TypeCache CACHE = new TypeCache.WithInlineExpunction(
			TypeCache.Sort.WEAK );

	private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

	/**
	 * Access to ByteBuddy. It's almost equivalent to creating a new ByteBuddy instance,
	 * yet slightly preferrable so to be able to reuse the same instance.
	 * @return
	 */
	public ByteBuddy getCurrentyByteBuddy() {
		return buddy;
	}

	/**
	 * @deprecated as we should not need static access to this state.
	 * This will be removed with no replacement.
	 * It's actually likely that this whole class becomes unnecessary in the near future.
	 */
	@Deprecated
	public static TypeCache getCacheForProxies() {
		return CACHE;
	}

	/**
	 * Wipes out all known caches used by ByteBuddy. This implies it might trigger the need
	 * to re-create some helpers if used at runtime, especially as this state is shared by
	 * multiple SessionFactory instances, but at least ensures we cleanup anything which is no
	 * longer needed after a SessionFactory close.
	 * The assumption is that closing SessionFactories is a rare event; in this perspective the cost
	 * of re-creating the small helpers should be negligible.
	 */
	void clearState() {
		CACHE.clear();
	}

	/**
	 * @deprecated as we should not need static access to this state.
	 * This will be removed with no replacement.
	 * It's actually likely that this whole class becomes unnecessary in the near future.
	 */
	@Deprecated
	public static ByteBuddy getStaticByteBuddyInstance() {
		return buddy;
	}

	public static ClassLoadingStrategy resolveClassLoadingStrategy(Class originalClass) {
		if ( ClassInjector.UsingLookup.isAvailable() ) {
			// This is only enabled for JDK 9+

			Method privateLookupIn;
			try {
				privateLookupIn = MethodHandles.class.getMethod( "privateLookupIn", Class.class, MethodHandles.Lookup.class );
			}
			catch (Exception e) {
				throw new HibernateException( LOG.bytecodeEnhancementFailed( originalClass.getName() ), e );
			}

			try {
				Object privateLookup;

				try {
					privateLookup = privateLookupIn.invoke( null, originalClass, LOOKUP );
				}
				catch (InvocationTargetException exception) {
					if ( exception.getCause() instanceof IllegalAccessException ) {
						return new ClassLoadingStrategy.ForUnsafeInjection( originalClass.getProtectionDomain() );
					}
					else {
						throw new HibernateException( LOG.bytecodeEnhancementFailed( originalClass.getName() ), exception.getCause() );
					}
				}

				return ClassLoadingStrategy.UsingLookup.of( privateLookup );
			}
			catch (Throwable e) {
				throw new HibernateException( LOG.bytecodeEnhancementFailedUnableToGetPrivateLookupFor( originalClass.getName() ), e );
			}
		}
		else {
			return new ClassLoadingStrategy.ForUnsafeInjection( originalClass.getProtectionDomain() );
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy