Skip to content

Don't generate getters for inaccessible getters made accessible - #377

Merged
cowtowncoder merged 6 commits into
2.xfrom
blackbird-nondefault-hidden-getter
Nov 3, 2026
Merged

cowtowncoder merged 6 commits into
2.xfrom
blackbird-nondefault-hidden-getter

Conversation

@cowtowncoder

Copy link
Copy Markdown
Member

Problem

With a class-level @JsonInclude(NON_DEFAULT), databind's PropertyBuilder makes each getter accessible (to read the default bean's values) before Blackbird's changeProperties sees it. lookup.unreflect skips its access checks for an accessible Method, so a getter the generated accessor can't call is no longer refused there, and canLinkAccessor passes too.

For a bean inheriting a package-private @JsonProperty getter from a superclass in another package, LambdaMetafactory then rejects the handle, and every serialization of the bean fails (plain databind writes it fine):

  • JDK 17, 21: RuntimeException: LambdaConversionException: MethodHandle(...)int is not direct or cannot be cracked
  • JDK 11: InvalidDefinitionException: IllegalAccessException: member is private to package

This also happens with 2.22.4, so it isn't a regression from #366. Without NON_DEFAULT, the getter isn't accessible yet, and #366's existing fallback works.

Fix

Unreflect a copy of the getter that isn't accessible, as the deserializer side already does for setters. The helper moves from BBDeserializerModifier to ReflectionHack.withoutAccessOverride so both modifiers use it. The serializer also catches the same exceptions as the deserializer (NoSuchMethodException, SecurityException).

Tests

New TestInaccessibleGetterTypes.testInheritedGetterMadeAccessible: output matches vanilla, the hidden getter is left to BeanPropertyWriter, and the bean's own getter is still optimized. It fails without the fix. The Blackbird suite passes locally on JDK 11, 17 and 21; JDK 8 wasn't available locally.

…ible

With a class-level `@JsonInclude(NON_DEFAULT)`, databind makes the getters
accessible (to read the default bean's values) before Blackbird sees them.
`unreflect` then skips its access checks, so an inherited package-private
getter from another package got a generated getter that `LambdaMetafactory`
rejects, failing every serialization of the bean. Unreflect a copy that
isn't accessible, as the deserializer side already does; the helper moves
to `ReflectionHack` for both.
@cowtowncoder cowtowncoder added 2.23 blackbird Issue related to Blackbird module labels Nov 3, 2026
@cowtowncoder cowtowncoder changed the title Blackbird: don't generate getters for inaccessible getters made accessible Don't generate getters for inaccessible getters made accessible Nov 3, 2026
…s one

`getDeclaredMethod` picks by name and parameters only, so for a bridge
method (or the method it bridges to) it could return the other one, with
a different return type.
@cowtowncoder
cowtowncoder merged commit 4955ca4 into 2.x Nov 3, 2026
4 checks passed
@cowtowncoder
cowtowncoder deleted the blackbird-nondefault-hidden-getter branch November 3, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.23 blackbird Issue related to Blackbird module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant