Skip to content

Reject unbalanced parentheses in profile expressions#36550

Open
daguimu wants to merge 1 commit intospring-projects:mainfrom
daguimu:fix/profiles-parser-unbalanced-parentheses-36540
Open

Reject unbalanced parentheses in profile expressions#36550
daguimu wants to merge 1 commit intospring-projects:mainfrom
daguimu:fix/profiles-parser-unbalanced-parentheses-36540

Conversation

@daguimu
Copy link
Copy Markdown

@daguimu daguimu commented Mar 27, 2026

Problem

ProfilesParser silently accepts unbalanced parentheses in profile expressions. For example, Profiles.of("dev)") or @Profile("dev)") is accepted without error and treated as "dev". This can lead to unexpected behavior where malformed profile annotations are silently interpreted instead of being rejected.

Root Cause

In ProfilesParser.parseTokens(), when a closing ) is encountered outside of a Context.PARENTHESIS context (i.e., without a matching opening (), the parser merges the current elements, clears state, and continues parsing instead of raising a validation error. Similarly, when all tokens are consumed while still inside a PARENTHESIS context (unmatched opening (), the method returns normally without detecting the imbalance.

Fix

  • In the ")" case of parseTokens(), reject unmatched closing parentheses by calling assertWellFormed(expression, false) when not in PARENTHESIS context, instead of silently continuing
  • After the token loop, add assertWellFormed(expression, context != Context.PARENTHESIS) to reject unmatched opening parentheses when tokens are exhausted
  • Fix an existing test (ofAndExpressionWithoutSpaces) that inadvertently relied on this lenient behavior by using "spring&framework)" instead of "(spring&framework)"

Tests Added

Change Point Test
Reject unmatched ) at top level malformedExpressionsWithUnbalancedParentheses() — verifies "dev)", "spring&framework)", "(dev))" all throw IllegalArgumentException
Reject unmatched ( when tokens exhaust malformedExpressionsWithUnbalancedParentheses() — verifies "(dev", "((dev)" throw IllegalArgumentException
Fix existing test input ofAndExpressionWithoutSpaces() — now uses "(spring&framework)" and still passes assertAndExpression checks

All 37 tests in ProfilesTests pass, including all pre-existing tests (no regressions).

Impact

Expressions with unbalanced parentheses that were previously silently accepted will now throw IllegalArgumentException with a "Malformed profile expression" message. This is consistent with the existing behavior for standalone "(" and ")" which already throw. Well-formed expressions are not affected.

Fixes #36540

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 27, 2026
ProfilesParser.parseTokens() silently accepts unbalanced parentheses
in profile expressions such as "dev)" or "(dev", treating them as
valid. This can lead to unexpected behavior where malformed @Profile
annotations are silently interpreted instead of being rejected.

This commit tightens the validation in parseTokens() to reject:
- Unmatched closing parenthesis at the top level
- Unmatched opening parenthesis when tokens are exhausted

Also fixes an existing test that inadvertently relied on this lenient
behavior by using "spring&framework)" instead of "(spring&framework)".

Fixes spring-projectsgh-36540

Signed-off-by: daguimu <daguimu.geek@gmail.com>
@daguimu daguimu force-pushed the fix/profiles-parser-unbalanced-parentheses-36540 branch from 63c73f3 to d3ac9ca Compare March 27, 2026 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ProfilesParser silently accepts unbalanced parentheses in profile expressions

2 participants