Skip to content

Fix: UnsupportedOperationException when resolving method calls inside lambdas in Comparator.comparing (#2716)#5026

Merged
jlerbsc merged 2 commits into
javaparser:masterfrom
jlerbsc:master
May 27, 2026
Merged

Fix: UnsupportedOperationException when resolving method calls inside lambdas in Comparator.comparing (#2716)#5026
jlerbsc merged 2 commits into
javaparser:masterfrom
jlerbsc:master

Conversation

@jlerbsc

@jlerbsc jlerbsc commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2716 .

Resolving method calls on implicit lambda parameters (e.g. a.getName() in
Comparator.comparing(a -> a.getName())) crashed with an
UnsupportedOperationException when the lambda was used inside a stream chain
on a user-defined element type.

Root cause

Comparator.comparing is a static generic method, so the scope-based type
parameter substitution that works for instance calls (e.g. stream.map(...))
is never taken. Its type parameter T therefore remained as an unresolved
TypeVariable, which caused two cascading failures:

  1. LambdaExprContext.solveSymbolAsValue returned a constraint type whose
    bound was an unresolved TypeVariable T, and
  2. AbstractJavaParserContext.findTypeDeclarations had no handler for that
    shape, throwing UnsupportedOperationException.
    Fix

LambdaExprContext.java — outer-context type parameter inference:
When the enclosing method call (e.g. comparing(...)) is itself an
argument of another method call with a known receiver type (e.g.
stream.sorted(...)), infer the static method's type parameters from the
outer call's expected parameter type. Concretely, the pair
(comparing's return type Comparator<T>) ↔ (sorted's expected type
Comparator<? super A>) is registered in the InferenceContext, letting
the engine resolve T → ? super A and thus determine the lambda
parameter type.
AbstractJavaParserContext.java — extended constraint-type handling in
findTypeDeclarations:
Added two new sub-cases inside the isConstraint() branch:

  • isTypeVariable(): the bound is still an unresolved type variable
    (fallback when outer-context inference is unavailable); use the
    variable's explicit upper bounds, defaulting to Object.
  • isWildcard() && isSuper(): the bound is ? super X produced by the
    outer-context inference; use X's type declaration (with the same
    TypeVariable fallback for X if needed).
    Tests

  • LambdaExprContextResolutionTest: unit test verifying that
    solveSymbolAsValue("s") on the lambda in
    stream.sorted(Comparator.comparing(s -> s.toLowerCase())) returns
    ? super java.lang.String.
  • LambdaResolutionTest: two integration tests — one asserting that all
    method calls in a stream chain with a user-defined element type resolve
    without throwing (direct regression for Cannot resolve sorted() in streams #2716), and one asserting the
    precise qualified signature of toLowerCase() when the element type is
    String.

@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.693%. Comparing base (d3c103b) to head (11df31a).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...arsermodel/contexts/AbstractJavaParserContext.java 0.000% 28 Missing ⚠️
...er/javaparsermodel/contexts/LambdaExprContext.java 88.888% 1 Missing and 3 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@               Coverage Diff               @@
##              master     #5026       +/-   ##
===============================================
- Coverage     58.699%   58.693%   -0.007%     
- Complexity      2587      2595        +8     
===============================================
  Files            702       702               
  Lines          40213     40277       +64     
  Branches        7325      7340       +15     
===============================================
+ Hits           23605     23640       +35     
- Misses         13636     13663       +27     
- Partials        2972      2974        +2     
Flag Coverage Δ
AlsoSlowTests 58.693% <50.000%> (-0.007%) ⬇️
javaparser-core 58.693% <50.000%> (-0.007%) ⬇️
javaparser-symbol-solver 58.693% <50.000%> (-0.007%) ⬇️
jdk-10 58.264% <50.000%> (-0.006%) ⬇️
jdk-11 58.265% <50.000%> (-0.006%) ⬇️
jdk-12 58.265% <50.000%> (-0.006%) ⬇️
jdk-13 58.265% <50.000%> (-0.004%) ⬇️
jdk-14 58.496% <50.000%> (-0.004%) ⬇️
jdk-15 58.496% <50.000%> (-0.007%) ⬇️
jdk-16 58.471% <50.000%> (-0.007%) ⬇️
jdk-17 58.620% <50.000%> (-0.004%) ⬇️
jdk-18 58.620% <50.000%> (-0.007%) ⬇️
jdk-8 58.100% <50.000%> (-0.008%) ⬇️
jdk-9 58.261% <50.000%> (-0.009%) ⬇️
macos-latest 58.668% <50.000%> (-0.007%) ⬇️
ubuntu-latest 58.663% <50.000%> (-0.007%) ⬇️
windows-latest 58.676% <50.000%> (-0.007%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...er/javaparsermodel/contexts/LambdaExprContext.java 80.891% <88.888%> (+4.858%) ⬆️
...arsermodel/contexts/AbstractJavaParserContext.java 61.878% <0.000%> (-11.325%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 670a7a1...11df31a. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jlerbsc jlerbsc merged commit ba4bbd8 into javaparser:master May 27, 2026
62 of 64 checks passed
@jlerbsc jlerbsc added this to the next release milestone May 27, 2026
@jlerbsc jlerbsc added the PR: Fixed A PR that offers a fix or correction label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: Fixed A PR that offers a fix or correction

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot resolve sorted() in streams

1 participant