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.