Repository: FasterXML/jackson-databind (Java)

Issue:
jackson-databind 3.0.0 renders `callbacks` property from Spring CGLIB Proxy
### Search before asking

- [x] I searched in the [issues](https://github.com/FasterXML/jackson-databind/issues) and found nothing similar.

### Describe the bug

jackson-databind 3.0.0 renders the `callbacks` property from Spring CGLIB Proxy which appears to be a regression of https://github.com/FasterXML/jackson-databind/issues/674 that occurred in https://github.com/FasterXML/jackson-databind/commit/be906756305ee727d6cb0a44376ca77b39e593fe

This change broke Spring Security's / Jackson tests that confirm that objects secured using Spring Security proxies do not render properties on the proxy itself. Details can be found at https://github.com/spring-projects/spring-security/issues/18077

Can the ignoring of CGLIB be restored? If not, what is the reason and what is the recommended way that users should restore this behavior in Jackson 3?

### Version Information

tools.jackson.core:jackson-databind-3.0.0

### Reproduction

A complete example of the `callbacks` property not being rendered [in Jackson 2](https://github.com/rwinch/spring-sample/blob/jackson-cglib-properties/src/jackson2/java/jackson2/CglibTest.java#L16) and [rendering callbacks property in Jackson 3](https://github.com/rwinch/spring-sample/blob/jackson-cglib-properties/src/jackson3/java/jackson3/CglibTest.java) can be found at https://github.com/rwinch/spring-sample/tree/jackson-cglib-properties You can run `./gradlew check` to perform checks for both Jackson 2 and Jackson 3 or `./gradlew jackson2` and `./gradlew jackson3` to run the tests separately.


```java
static class Person {
	private final String firstName;

	private final String lastName;

	public Person(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}
}

@Test
public void cglibPropertiesNotRendered() throws Exception {
	JsonMapper mapper = JsonMapper.builder().build();
	Person target = new Person("first", "last");
	ProxyFactory factory = new ProxyFactory(target); // ProxyFactory from org.springframework:spring-aop:7.0.0-RC1
	factory.setOpaque(true);

	Person proxied = (Person) factory.getProxy();
	String json = mapper.writeValueAsString(proxied);
	Map<String, Object> properties = mapper.readValue(json, new TypeReference<>() {
	});
	assertThat(properties).containsOnlyKeys("firstName", "lastName"); // fails because callbacks property is included
}
``` 


### Expected behavior

I'd expect that Jackson 3 does not render CGLIB proxy properties.

### Additional context

_No response_


Discussion:
Jackson is a low level lib. We don't normally POCs that involve 3rd party libs. Is there a way to reproduce this with needing 3rd party libs like the Spring ones?
Ok first we do need full reproduction -- test looks like almost that, just need `import`s & dependency to add in `pom.xml` ("test" dependency).

I suspect test needs to be added in 2.x to guard against regression, merge into 3.x, see if we can restore blocking.

As to changes, looks like

    src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java

has references to cglib from comments. So logic must have been refactored, but regression not detected.

> Jackson is a low level lib. We don't normally POCs that involve 3rd party libs. Is there a way to reproduce this with needing 3rd party libs like the Spring ones?

I'm pretty sure it can be reproduced without Spring & Spring was mentioned as context.
Our existing tests did not use actual cglib for tests tho.


Thank you for the quick replies.

> Ok first we do need full reproduction -- test looks like almost that, just need imports & dependency to add in pom.xml ("test" dependency).

The branch in the GitHub repository that I posted has a complete reproducer (it demos working with jackson2 and failing with jackson3) https://github.com/rwinch/spring-sample/tree/jackson-cglib-properties Details in the original report.

> I'm pretty sure it can be reproduced without Spring & Spring was mentioned as context.
> Our existing tests did not use actual cglib for tests tho.

I can provide a mocked test, but if Spring's support changes then the test would need to be updated.
Ah. I missed this:

    // ProxyFactory from org.springframework:spring-aop:7.0.0-RC1

Tests we include cannot really have dependencies to Spring libraries: cglib is fine. So we'd reproduction without Spring but with cglib, ideally; mock only if we have no other choice.

**EDIT**: we could have more extensive interation tests on:

https://github.com/FasterXML/jackson-integration-tests

where Spring dependencies would be ok. For what that is worth.


@cowtowncoder You should be able to import the branch from my github repository into an IDE to run the full test. The snippet was just to help for record keeping. 

I'm happy to provide a unit test that aligns with jackson-databind project. The sample I provided was meant to be an easy way to run a full integration test of what was happening rather than be used as a test by Jackson. Note that a dependency on cglib won't work since Spring and Hibernate repackage cglib, but we can mock it.

Would you like me to provide a test for jackson-databind that does not have a dependency?
Sounds good. I will provide tests with no additional dependencies for jackson-databind that simulate the issue :)
Right, I appreciate your help! For fixing things, it'd be very helpful to have a jackson-databind unit test that uses cglib produced/modified value(s) that emulates Spring problem.

@cowtowncoder I've sent two PRs

* https://github.com/FasterXML/jackson-databind/pull/5356 - This adds the unit tests to 2.x to prevent a regression
* https://github.com/FasterXML/jackson-databind/pull/5357 - This merges the previous pull request into 3.x and adds a second commit that fixes it
@cowtowncoder Thanks for getting this fixed. I noticed that the [3.0.1 milestone is open](https://github.com/FasterXML/jackson-databind/milestone/194) but the [3.0.1 tag](https://github.com/FasterXML/jackson-databind/releases/tag/jackson-databind-3.0.1) is published and [jackson-databind-3.0.1 is in central](https://central.sonatype.com/artifact/tools.jackson.core/jackson-databind/3.0.1). Should the milestone be closed?



Patch:
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index d399a7b0d4..f741e01cae 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -87,3 +87,8 @@ Dónal Murtagh (@donalmurtagh)
 Phil Clay (@philsttr)
  * Reported #5344: "Unexpected end-of-input" for `JsonParser.readValueAs()` (in 3.0)
   [3.0.1]
+
+Rob Winch (@rwinch)
+ * Reported, contributed fix for #5354: jackson-databind 3.0.0 renders `callbacks`
+   property from Spring CGLIB Proxy
+  [3.0.1]
diff --git a/release-notes/VERSION b/release-notes/VERSION
index b7f65b1048..ea306dc7ce 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -16,6 +16,8 @@ Versions: 3.x (for earlier see VERSION-2.x)
  (reported by @Artur)
 #5344: "Unexpected end-of-input" for `JsonParser.readValueAs()` (in 3.0)
  (reported by Phil C)
+#5354: jackson-databind 3.0.0 renders `callbacks` property from Spring CGLIB Proxy
+ (reported, fix contributed by Rob W)
 
 3.0.0 (03-Oct-2025)
 
diff --git a/src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java b/src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java
index f4c1c94128..7106d6e35a 100644
--- a/src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java
+++ b/src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java
@@ -110,14 +110,12 @@ public String findNameForRegularGetter(AnnotatedMethod am, String name)
             // coverage without false matches; but for now let's assume there is
             // no reason to use any such getter from CGLib.
 
-            // 05-Oct-2020, tatu: Removed from Jackson 3.0
-            /*
+            // 20-Oct-2025 https://github.com/FasterXML/jackson-databind/issues/5354
             if ("getCallbacks".equals(name)) {
                 if (_isCglibGetCallbacks(am)) {
                     return null;
                 }
-            } else */
-            if ("getMetaClass".equals(name)) {
+            } else if ("getMetaClass".equals(name)) {
                 // 30-Apr-2009, tatu: Need to suppress serialization of a cyclic reference
                 if (_isGroovyMetaClassGetter(am)) {
                     return null;
@@ -198,8 +196,7 @@ protected String stdManglePropertyName(final String basename, final int offset)
     // name "getCallbacks" and we need to determine if it is indeed injected
     // by Cglib. We do this by verifying that the  result type is "net.sf.cglib.proxy.Callback[]"
 
-    // 05-Oct-2020, tatu: Removed from 3.0
-    /*
+    // 20-Oct-2025 https://github.com/FasterXML/jackson-databind/issues/5354
     protected boolean _isCglibGetCallbacks(AnnotatedMethod am)
     {
         Class<?> rt = am.getRawType();
@@ -222,7 +219,6 @@ protected boolean _isCglibGetCallbacks(AnnotatedMethod am)
         }
         return false;
     }
-    */
 
     // 05-Oct-2020, tatu: Left in 3.0 for now
     // Another helper method to deal with Groovy's problematic metadata accessors


Test patch:
diff --git a/src/test/java/tools/jackson/databind/ext/cglib/CglibFiltering5354Test.java b/src/test/java/tools/jackson/databind/ext/cglib/CglibFiltering5354Test.java
index ff96da7e76..437cc08cac 100644
--- a/src/test/java/tools/jackson/databind/ext/cglib/CglibFiltering5354Test.java
+++ b/src/test/java/tools/jackson/databind/ext/cglib/CglibFiltering5354Test.java
@@ -24,9 +24,6 @@ public class CglibFiltering5354Test
     @Test
     public void testWriteWithSpringCglibProxyDoesNotIncludeCallbacksProperty() throws Exception
     {
-        // 20-Oct-2025, tatu: Temporarily disable until #5357 merged
-        if (true) { return; }
-
         MockedSpringCglibProxy mockedProxy = new MockedSpringCglibProxy("hello");
         String json = MAPPER.writeValueAsString(mockedProxy);
         Map<?, ?> properties = MAPPER.readValue(json, Map.class);
@@ -34,7 +31,7 @@ public void testWriteWithSpringCglibProxyDoesNotIncludeCallbacksProperty() throw
     }
 
     // https://github.com/FasterXML/jackson-databind/issues/5354
-    //@Test
+    @Test
     public void testWriteWithHibernateCglibProxyDoesNotIncludeCallbacksProperty() throws Exception
     {
         MockedHibernateCglibProxy mockedProxy = new MockedHibernateCglibProxy("hello");
@@ -44,7 +41,7 @@ public void testWriteWithHibernateCglibProxyDoesNotIncludeCallbacksProperty() th
     }
 
     // https://github.com/FasterXML/jackson-databind/issues/5354
-    //@Test
+    @Test
     public void testWriteWithNetCglibProxyDoesNotIncludeCallbacksProperty() throws Exception
     {
         MockedNetCglibProxy mockedProxy = new MockedNetCglibProxy("hello");