spring-projects / spring-projects/spring-grpc

BearerTokenAuthenticationInterceptor: lambda constructor call became ambiguous after adding TokenSupplier overload in 1.1.1

Open
#432 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
413
Forks
95
Avg merge
4d 6h
Merged PRs (30d)
2

Description

Bug description

Since 1.1.1 (added in #378), BearerTokenAuthenticationInterceptor has three constructors:

public BearerTokenAuthenticationInterceptor(String token) { ... }
public BearerTokenAuthenticationInterceptor(Supplier<String> token) { ... }
public BearerTokenAuthenticationInterceptor(TokenSupplier token) { ... }

Supplier<String> and TokenSupplier are both functional interfaces with a single, argument-less method returning String (get() vs. token()). Because they are structurally identical from the compiler's point of view, any call
site that passes an inline, un-targeted lambda expression to the constructor no longer compiles - it now fails with reference to BearerTokenAuthenticationInterceptor is ambiguous, because both the Supplier<String> and the
TokenSupplier overload are equally applicable.
This is a well-known Java overloading pitfall (see Effective Java, Item 52: "avoid overloading with different functional interface parameters in the same argument position") and effectively breaks source compatibility for existing
1.1.0 users who wrote code like:

new BearerTokenAuthenticationInterceptor(() -> jwt.getTokenValue())

even though adding a new overload is normally considered a backwards-compatible, additive change.

Steps to reproduce
  1. Take any code compiled against spring-grpc 1.1.0 that constructs a BearerTokenAuthenticationInterceptor with an inline lambda, e.g.:
    @Bean
    MyServiceGrpc.MyServiceBlockingStub myServiceBlockingStub(GrpcChannelFactory channels) {
      return MyServiceGrpc.newBlockingStub(channels.createChannel("myService"))
          .withInterceptors(
              new BearerTokenAuthenticationInterceptor(
                  () -> SecurityContextHolderJwtHelper.getJwt().getTokenValue()));
    }
    
  2. Bump spring-grpc to 1.1.1 (no other code changes).
  3. Compile.
Actual behavior

Compilation fails with:

reference to BearerTokenAuthenticationInterceptor is ambiguous
  both constructor BearerTokenAuthenticationInterceptor(java.util.function.Supplier<java.lang.String>) in org.springframework.grpc.client.interceptor.security.BearerTokenAuthenticationInterceptor
  and constructor BearerTokenAuthenticationInterceptor(org.springframework.grpc.client.interceptor.security.TokenSupplier) in org.springframework.grpc.client.interceptor.security.BearerTokenAuthenticationInterceptor match
Expected behavior

Adding the new TokenSupplier constructor in a patch/minor release should not silently break source compatibility for existing consumers using the previously-recommended inline-lambda style.

Possible fixes
  • Deprecate and eventually remove the Supplier<String> overload now that TokenSupplier exists, instead of keeping both indefinitely.
  • Alternatively, make TokenSupplier extend Supplier<String> (with a default token()/get() bridging method) so there is only one truly distinct SAM type at this argument position, removing the ambiguity.
  • At minimum, document this as a known source-incompatible change in the 1.1.1 release notes so users know to add an explicit cast ((TokenSupplier) () -> ... or (Supplier<String>) () -> ...) when upgrading.
Environment
  • spring-grpc: 1.1.1 (regression vs. 1.1.0)
  • Java: 21
  • Spring Boot: 4.x

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the BearerTokenAuthenticationInterceptor constructors and the TokenSupplier definition, then reproduce the Java 21 compilation failure with the inline lambda shown in the issue. Compare the proposed compatibility options and add regression coverage for the selected API behavior. Done means existing 1.1.0-style lambda call sites compile against 1.1.1 without ambiguity.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend-api-design, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.