Skip to content

[FREEMARKER-234] Expose Boolean isFoo() getters as bean properties#127

Open
mapeders wants to merge 1 commit intoapache:2.3-gaefrom
mapeders:FREEMARKER-234-boolean-wrapper-is-getter
Open

[FREEMARKER-234] Expose Boolean isFoo() getters as bean properties#127
mapeders wants to merge 1 commit intoapache:2.3-gaefrom
mapeders:FREEMARKER-234-boolean-wrapper-is-getter

Conversation

@mapeders
Copy link
Copy Markdown
Contributor

Summary

Fixes FREEMARKER-234: BeansWrapper did not expose isFoo() methods that return java.lang.Boolean (wrapper) as the foo bean property, even though the manual states that model.foo should invoke either obj.getFoo() or obj.isFoo(). The restriction to primitive boolean came from java.beans.Introspector, which is strict to the JavaBeans spec.

  • Gated behind incompatible_improvements2.3.35 — pre-existing configurations see no change.
  • ClassIntrospector.getPropertyDescriptors now supplements java.beans.Introspector's output by scanning for public Boolean isXxx() methods (mirroring the existing Java 8 default-method supplement path).
  • _MethodUtil.getBeanPropertyNameFromReaderMethodName accepts Boolean.class alongside boolean.class.
  • Static isFoo() and non-Boolean isFoo() (e.g. String isLabel()) remain excluded from property exposure.
  • Release notes entry + JavaDoc update under the "2.3.35 (or higher)" ICI change list.

Test plan

  • GetPropertyNameFromReaderMethodNameTest — flipped the assertion that codified the bug (isFoo + Boolean.class"foo"), added isF/Boolean.class symmetry.
  • New BeansWrapperMiscTest.booleanWrapperIsGetterAsPropertyTest — verifies:
    • At ICI 2.3.34 (legacy): .obsolete is missing and only the method form is reachable.
    • At ICI 2.3.35: .obsolete resolves to the wrapped Boolean, primitive boolean isActive() still works, String isLabel() is not exposed as a property, static Boolean isArchived() is not exposed as a property, and isObsolete remains reachable as a method.
  • Full core test suite: 871 tests, 0 failures (./gradlew :test --rerun-tasks).

When an incompatible_improvements of 2.3.35 or higher is set, isFoo()
methods that return java.lang.Boolean (the wrapper class) are now
exposed as the foo bean property, matching the long-standing behaviour
for primitive boolean and the contract promised in the manual.
java.beans.Introspector follows the strict JavaBeans spec and only
reports primitive-boolean is-getters, so ClassIntrospector now
supplements its result with a targeted scan (mirroring the pattern
already used for Java 8 default methods), and _MethodUtil accepts the
wrapper return type. Static methods, and isFoo() methods with any
other return type, remain excluded.
@chrisrueger
Copy link
Copy Markdown
Contributor

As stated in https://issues.apache.org/jira/browse/FREEMARKER-234 this is based on the Java Beans Specification Section 8.3.2 which is only for boolean not Boolean.

As suggested in the ticket, Freemarker should probably improve its documentation that isX() works with boolean, not with Boolean`.

@mapeders
Copy link
Copy Markdown
Contributor Author

Thanks @chrisrueger — fair point on 8.3.2, the current behavior is strictly
spec-compliant.

That said, the FreeMarker manual already says model.foo invokes getFoo() or
isFoo() without qualifying the return type, and the change here is gated
behind incompatible_improvements >= 2.3.35 (mirroring the existing Java 8
default-method supplement path in ClassIntrospector) — so existing configs see
no change.

Happy either way though: if the committers prefer a docs-only fix, I'll gladly
close this and open a documentation PR instead.

@ddekany
Copy link
Copy Markdown
Contributor

ddekany commented Apr 20, 2026

While this is not a bug, it's certainly quite annyoing and people keep running into it. But I will have to review the implementation to see if there's any cost involved that everyone has to pay, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants