HibernateProxyConverter.javaReflectionConverter to intercept any object that implements org.hibernate.proxy.HibernateProxy before XStream's reflection-based serialization kicks in. When a Hibernate proxy is encountered, it calls getHibernateLazyInitializer().getImplementation() to extract the underlying entity instance, then delegates marshalling to the appropriate converter for the real class. Without this converter, XStream would serialize the Javassist/CGLIB-generated proxy object (a meaningless shell containing only a lazy initializer), resulting in empty or broken XML output for any lazily-loaded entity association.HibernateProxyConverter extends com.thoughtworks.xstream.converters.reflection.ReflectionConverter, which is XStream's default converter for objects that don't have a more specific converter. It uses reflection to walk fields and serialize them. By extending this base class, the converter automatically inherits all the standard reflection-based serialization behavior — it only overrides the proxy-related interception points.
| Field | Type | Purpose |
|---|---|---|
converterLookup | ConverterLookup | Reference to XStream's converter registry. Used at marshal time to delegate to the correct converter for the unwrapped entity's real class. Set via constructor injection. |
Returns true for any class that HibernateProxy.class.isAssignableFrom(clazz). This matches all Javassist/CGLIB-generated Hibernate proxy classes (which implement the HibernateProxy interface). When this returns true, XStream routes marshalling through this converter instead of the default ReflectionConverter.
ReflectionConverter in XStream's converter chain, otherwise the default converter would claim the proxy first (since proxies are regular classes) and serialize the proxy internals instead of the real entity.The core unwrapping logic:
item instanceof HibernateProxy.((HibernateProxy) arg0).getHibernateLazyInitializer().getImplementation() to get the real entity. The LazyInitializer.getImplementation() call forces initialization of the proxy — this triggers a database query if the entity hasn't been loaded yet.converterLookup.lookupConverterForType(item.getClass()) to find the appropriate converter for the real entity class, then calls converter.marshal(item, writer, context). This ensures the real entity is serialized using the correct converter (potentially this same HibernateProxyConverter if the real entity is also a proxy, or the standard reflection converter otherwise).This converter does not override unmarshal(). During deserialization, XStream creates standard Java objects — there is no need to create Hibernate proxies from XML. The deserialized fields are set on the entity via reflection, and Hibernate wraps them when the entity is later persisted or merged.
LazyInitializer interface — if a future Hibernate version changes how proxies expose their underlying entity, this converter would need updating.getImplementation() forces the lazy proxy to load. This means XML export of an entity graph may trigger cascading database queries for every lazily-loaded association. The caller must ensure the Hibernate session stays open and should consider using JOIN FETCH or OpenSessionInView patterns to pre-load associations before serialization.HibernateProxyConverter again, and the unwrapping repeats. This eventually terminates because the chain bottoms out at the real entity class.item.getClass() (the real entity's class) rather than the proxy class. This means any custom converters registered for specific entity types will be correctly selected, not bypassed by the proxy wrapper.class HibernateProxyConverter without public), indicating it is an internal implementation detail of the persistence.xstream package, not intended for direct use outside the framework.arg0, arg1 parameter names — a legacy Java style suggesting this code originated in an older version of the codebase.868d6abb7 2025 -> 2026 63081666f Source file headers: 2024-> 2025. b6092df09 Copyright 2023 -> 2024 ab45d51fa Copyright 2001-2022 -> 2001-2023. 5f7ef41b8 Copyright 2021 -> 2022 ceb63e8a1 Source code header: (C) 2001-2021. 7c79f1922 Copyright of source header -> 2020. 32f634b88 Optimize imports dd5ca38ac CopyRight of all java file-header updated or created. 9ebb88522 Initial commit