Skip to content

feat: add null-safe navigation operator (?.) for Java 8 compatibility#497

Merged
lukaszlenart merged 2 commits intoognl-3-4-xfrom
feat/null-safe-operator
Nov 29, 2025
Merged

feat: add null-safe navigation operator (?.) for Java 8 compatibility#497
lukaszlenart merged 2 commits intoognl-3-4-xfrom
feat/null-safe-operator

Conversation

@lukaszlenart
Copy link
Copy Markdown
Collaborator

Summary

Port the null-safe navigation operator (?.) from main branch to ognl-3-4-x branch, enabling safer null handling for Java 8 users.

Key Features:

  • New ?. operator for null-safe property navigation
  • Returns null instead of throwing exceptions when encountering null intermediate values
  • Fully backward compatible with existing OGNL expressions
  • 100% Java 8 compatible (no Java 9+ features)

Ported from:

Changes

Grammar/Parser (src/main/javacc/ognl.jj)

  • Added SAFE_DOT token for ?. operator
  • Modified navigationChain() production rule to detect and flag null-safe navigation

Core Implementation (src/main/java/ognl/ASTChain.java)

  • Added nullSafe field with getter/setter
  • Updated getValueBody() to return null on encountering null intermediate values
  • Modified toString() to output ?. when nullSafe is true
  • Added shouldAppendNavigationOperator() helper method

Test Suite (61+ tests)

  • NullSafeOperatorTest.java - 26 tests for basic functionality
  • NullSafeCollectionTest.java - 13 tests for collections
  • NullSafeCompilationTest.java - 6 tests for compilation
  • NullSafeIntegrationTest.java - 16 tests for edge cases

Examples

// Basic null-safe navigation
user?.profile?.city              // Returns null if any part is null

// Method calls
user?.getProfile()?.getBio()     // Returns null if any part is null

// Collections
users?.{name}                    // Returns null if users is null
users?.{? #this.age > 18}        // Returns null if users is null

// Variables
#myVar?.someProperty              // Returns null if #myVar is null

// Mixed safe/unsafe
user.profile?.address.city       // Flexible combination

Test Results

All 947 tests pass (including 61+ new null-safe operator tests)

Tests run: 947, Failures: 0, Errors: 0, Skipped: 0

Differences from Main Branch

  • No shortCircuit logic: The ognl-3-4-x branch doesn't have the shortCircuit system property, so that logic was intentionally skipped
  • Java 8 compatible: Uses Arrays.asList() instead of List.of(), traditional casting instead of pattern matching
  • Backward compatible: All existing tests pass without modification

Test Plan

  • All existing tests pass (947 tests)
  • New null-safe operator tests pass (61+ tests)
  • Parser successfully recognizes ?. syntax
  • Null-safe navigation returns null on encountering null values
  • toString() correctly outputs ?. operator
  • Backward compatibility verified (existing expressions unchanged)
  • Java 8 compatibility verified (no Java 9+ APIs used)

🤖 Generated with Claude Code

lukaszlenart and others added 2 commits November 18, 2025 17:21
Add SAFE_DOT token and modify navigationChain production rule
to support null-safe navigation syntax (user?.profile?.city).

The parser now recognizes the ?. operator and sets a nullSafe
flag on ASTChain nodes, enabling null-safe property navigation
that returns null instead of throwing exceptions when encountering
null intermediate values.

Ported from main branch PRs #484 and #496.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add nullSafe field and null-checking logic in getValueBody().
Returns null when encountering null intermediate values instead
of throwing exceptions.

Update toString() to output ?. operator when nullSafe flag is set.
Add helper method shouldAppendNavigationOperator() to reduce
cognitive complexity.

This enables expressions like:
- user?.profile?.city (returns null if any part is null)
- items?.{? #this > 0} (null-safe collection operations)
- #var?.method() (null-safe method calls)

Ported from main branch PRs #484 and #496, adapted for Java 8
compatibility (ognl-3-4-x branch).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
24.1% Coverage on New Code (required ≥ 80%)
C Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@lukaszlenart
Copy link
Copy Markdown
Collaborator Author

@FHannes ported into 3.4.x

@lukaszlenart lukaszlenart added this to the 3.4.9 milestone Nov 18, 2025
@lukaszlenart lukaszlenart merged commit 4d89ca5 into ognl-3-4-x Nov 29, 2025
4 of 7 checks passed
@lukaszlenart lukaszlenart deleted the feat/null-safe-operator branch November 29, 2025 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant