Woops, I realized that HibernateBasicProxy is not actually the type but just a naming suffix. So basically what I have in my application are proxies generated by BasicProxyFactoryImpl:
public class BasicProxyFactoryImpl implements BasicProxyFactory {
private static final Class[] NO_INTERFACES = new Class[0];
private static final String PROXY_NAMING_SUFFIX = Environment.useLegacyProxyClassnames() ? "HibernateBasicProxy$" : "HibernateBasicProxy";
private final Class proxyClass;
private final ProxyConfiguration.Interceptor interceptor;
@SuppressWarnings("unchecked")
public BasicProxyFactoryImpl(Class superClass, Class[] interfaces, ByteBuddyState bytebuddy) {
if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) {
throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" );
}
final Class<?> superClassOrMainInterface = superClass != null ? superClass : interfaces[0];
this.proxyClass = bytebuddy.getCurrentyByteBuddy()
.with( new NamingStrategy.SuffixingRandom( PROXY_NAMING_SUFFIX, new NamingStrategy.SuffixingRandom.BaseNameResolver.ForFixedValue( superClassOrMainInterface.getName() ) ) )
.subclass( superClass == null ? Object.class : superClass, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR )
.implement( interfaces == null ? NO_INTERFACES : interfaces )
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )
.method( ElementMatchers.isVirtual().and( ElementMatchers.not( ElementMatchers.isFinalizer() ) ) )
.intercept( MethodDelegation.to( ProxyConfiguration.InterceptorDispatcher.class ) )
.implement( ProxyConfiguration.class )
.intercept( FieldAccessor.ofField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME ).withAssigner( Assigner.DEFAULT, Assigner.Typing.DYNAMIC ) )
.make()
.load( superClassOrMainInterface.getClassLoader(), ByteBuddyState.resolveClassLoadingStrategy( superClassOrMainInterface ) )
.getLoaded();
this.interceptor = new PassThroughInterceptor( proxyClass.getName() );
}
public Object getProxy() {
try {
final ProxyConfiguration proxy = (ProxyConfiguration) proxyClass.newInstance();
proxy.$$_hibernate_set_interceptor( this.interceptor );
return proxy;
}
catch (Throwable t) {
throw new HibernateException( "Unable to instantiate proxy instance", t );
}
}
public boolean isInstance(Object object) {
return proxyClass.isInstance( object );
}
}
The problem is that these proxies does not implement the HibernateProxy-interface, causing the unproxy-method to return the proxy again. I have tried manually adding the HibernateProxy-interface to my proxies like this:
static Object getProxyInstance(
Class persistentClass,
Set<Property> persistentProperties,
ExtentManager extentManager)
throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
if ( Modifier.isFinal( persistentClass.getModifiers() ) ) {
// Use the default constructor, because final classes cannot be inherited.
return useDefaultConstructor( persistentClass );
}
final ProxyConfiguration proxy = (ProxyConfiguration) Environment.getBytecodeProvider()
.getProxyFactoryFactory()
.buildBasicProxyFactory( persistentClass, new Class[] { TrackableEntity.class, HibernateProxy.class } )
.getProxy();
proxy.$$_hibernate_set_interceptor( new EntityProxyMethodHandler(
proxy,
persistentClass.getName(),
persistentProperties,
extentManager
) );
return proxy;
}
However, if I do this then the hibernateProxy.getHibernateLazyInitializer() returns null instead. I need to access the real object somehow, because right now the MethodInterceptor gets stuck, causing an endless loop of calls to itself, resulting in StackOverflowException.
public class EntityProxyMethodHandler implements ProxyConfiguration.Interceptor, Serializable {
private final EntityTracker entityTracker;
private final Object proxiedObject;
private final String proxiedClassName;
// private AutofetchLazyInitializer initializer;
EntityProxyMethodHandler(
Object proxiedObject,
String proxiedClassName,
Set<Property> persistentProperties,
ExtentManager extentManager) {
this.proxiedObject = proxiedObject;
this.proxiedClassName = proxiedClassName;
this.entityTracker = new EntityTracker(persistentProperties, extentManager );
// initializer = ((AutofetchLazyInitializer) ((HibernateProxy)proxiedObject).getHibernateLazyInitializer());
}
@Override
@RuntimeType
public Object intercept(@This Object instance, @Origin Method method, @AllArguments Object[] arguments)
throws Exception {
final String methodName = method.getName();
if ( "toString".equals( methodName ) ) {
return proxiedClassName + "@" + System.identityHashCode( instance );
}
else if ( "equals".equals( methodName ) ) {
return proxiedObject == instance;
}
else if ( "hashCode".equals( methodName ) ) {
return System.identityHashCode( instance );
}
else if ( arguments.length == 0 ) {
switch ( methodName ) {
case "disableTracking": {
boolean oldValue = entityTracker.isTracking();
entityTracker.setTracking( false );
return oldValue;
}
case "enableTracking": {
boolean oldValue = entityTracker.isTracking();
entityTracker.setTracking( true );
return oldValue;
}
case "isAccessed":
return entityTracker.isAccessed();
default:
break;
}
}
else if ( arguments.length == 1 ) {
if ( methodName.equals( "addTracker" ) && method.getParameterTypes()[0].equals( Statistics.class ) ) {
entityTracker.addTracker( (Statistics) arguments[0] );
return null;
}
else if ( methodName.equals( "addTrackers" ) && method.getParameterTypes()[0].equals( Set.class ) ) {
@SuppressWarnings("unchecked")
Set<Statistics> newTrackers = (Set) arguments[0];
entityTracker.addTrackers( newTrackers );
return null;
}
else if ( methodName
.equals( "extendProfile" ) && method.getParameterTypes()[0].equals( Statistics.class ) ) {
entityTracker.extendProfile( (Statistics) arguments[0], instance );
return null;
}
else if ( methodName
.equals( "removeTracker" ) && method.getParameterTypes()[0].equals( Statistics.class ) ) {
entityTracker.removeTracker( (Statistics) arguments[0] );
return null;
}
}
// Object unproxiedEntity = Hibernate.unproxy(proxiedObject);
// Object realObject = initializer.getTarget();
entityTracker.trackAccess( instance );
// TODO (ammachado): Here the real instance should be used, but how?
return method.invoke( instance, arguments );
}
}
It seems like the MethodHandler intercepts everytime we call getHibernateLazyInitializer(), calling the same method again as seen in the callstack down below, causing the StackOverflow.

Any ideas? Maybe a methodfilter should be used here? The problem that my proxies does not have any LazyInitializer associated to them still persists. This started when we changed to ByteBuddy proxies.