OptionalNotPresentToIsEmpty rewrites `!isPresent()` on a non-`java.util.Optional` type, producing uncompilable `isEmpty()`
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
- #1147 di @timtebeek — chiusa senza merge
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 70/100
Direzione di ricerca
Inizia da OptionalNotPresentToIsEmpty.java, in particolare dal MethodMatcher e dal modello di riscrittura citati alle righe 46 e 56. Riproduci la trasformazione con com.bazaarvoice.jolt.common.Optional, quindi aggiungi un test di regressione che dimostri che i receiver non risolti o non appartenenti al JDK rimangono invariati e che java.util.Optional continua a essere riscritto correttamente.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What version of OpenRewrite are you using?
- Gradle plugin
org.openrewrite:pluginv7.35.0 - rewrite-migrate-java v3.38.0
- Active recipe:
org.openrewrite.java.migrate.UpgradeToJava21(which pulls inorg.openrewrite.java.migrate.util.OptionalNotPresentToIsEmpty)
How are you running OpenRewrite?
Gradle plugin, applied via an init script over a large multi-module project:
rootProject {
plugins.apply(org.openrewrite.gradle.RewritePlugin)
dependencies {
rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.38.0")
}
rewrite {
activeRecipe("org.openrewrite.java.migrate.UpgradeToJava21")
setExportDatatables(true)
}
}
The affected module depends on Jolt (com.bazaarvoice.jolt:jolt-core:0.1.8), which ships its own
com.bazaarvoice.jolt.common.Optional<T>. That class exposes isPresent() and get() but has no
isEmpty() method (its full public API is empty(), of(T), get(), isPresent(), equals, toString).
The project is private, but the third-party type is public and small; the relevant snippet is below.
What is the smallest, simplest way to reproduce the problem?
The receiver is a Jolt Optional, not a JDK Optional:
import com.bazaarvoice.jolt.common.Optional; // NOT java.util.Optional
class ConvertMarkdownToHtmlRTL {
Optional<Object> applySingle(Object input) {
Optional<Object> baseHtmlOpt = convert(input);
if (!baseHtmlOpt.isPresent()) { // original, compiles fine
return Optional.empty();
}
// ...
}
}
What did you expect to see?
The code left unchanged. baseHtmlOpt is a com.bazaarvoice.jolt.common.Optional, not a
java.util.Optional, so the recipe should not apply. The recipe's MethodMatcher is in fact scoped to the
JDK type — new MethodMatcher("java.util.Optional isPresent()") with template
#{any(java.util.Optional)}.isEmpty()
(OptionalNotPresentToIsEmpty.java, lines 46 and 56 on v3.38.0) — so the intent is clearly JDK-only.
What did you see instead?
The recipe rewrote it to call isEmpty() on the Jolt type, which does not have that method, so the module
no longer compiles:
import com.bazaarvoice.jolt.common.Optional;
class ConvertMarkdownToHtmlRTL {
Optional<Object> applySingle(Object input) {
Optional<Object> baseHtmlOpt = convert(input);
if (baseHtmlOpt.isEmpty()) { // does not compile: no isEmpty() on com.bazaarvoice.jolt.common.Optional
return Optional.empty();
}
// ...
}
}
Because the JDK-scoped MethodMatcher nevertheless matched a com.bazaarvoice.jolt.common.Optional
receiver, this looks like the matcher firing when the receiver's type is unresolved/incompletely attributed
(the third-party Optional not being on the recipe's typed classpath), falling through to a name-only match
on isPresent(). A type-scoped migration recipe should not rewrite when it cannot positively confirm the
receiver is java.util.Optional — otherwise it silently emits uncompilable code with no warning or error from
the run itself.
- Note this is a distinct failure mode from #417/#418 (a
ClassCastExceptionthrown by the sibling
OptionalNotEmptyToIsPresent); here there is no crash — the recipe completes "successfully" and the breakage
only surfaces at the nextcompileJava.
What is the full stack trace of any errors you encountered?
No stack trace — the recipe run completes without error. The failure is a downstream Java compile error:
error: cannot find symbol
if (baseHtmlOpt.isEmpty()) {
^
symbol: method isEmpty()
location: variable baseHtmlOpt of type com.bazaarvoice.jolt.common.Optional<Object>
Are you interested in contributing a fix to OpenRewrite?
Open to it if you can point me at the preferred guard (e.g. requiring resolved receiver type before applying). Happy to add a recipe test that reproduces the mis-fire on a non-JDK Optional.
- Lingua principale
- Java
- Stelle
- 156
- Fork
- 129
- Merge medio
- 7h 12m
- PR unite (30g)
- 43
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di openrewrite/rewrite-migrate-java
-
bug
Difficoltà 3/5 Mezza giornata Idoneità per principianti 40/100
openrewrite/rewrite-migrate-java#1292 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
openrewrite/rewrite-migrate-java#1289 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 68/100
openrewrite/rewrite-migrate-java#1246 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 32/100
openrewrite/rewrite-migrate-java#1227 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 50/100
openrewrite/rewrite-migrate-java#1119 · 5 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di openrewrite/rewrite-migrate-java
Issue simili
-
`timer` rule rejects dates the engine acceptsForse già presa @MFA-G l’ha presa oggi. Apertabug ready
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
camunda/bpmnlint-plugin-camunda-compat#281 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
status: waiting-for-triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
AOT compilation fails for derived delete queries returning SetForse già presa @ryujungkyun l’ha presa oggi. Apertastatus: waiting-for-triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
spring-projects/spring-data-jpa#4387 ·
I maintainer di solito rispondono entro 3 giorni