OptionalNotPresentToIsEmpty rewrites `!isPresent()` on a non-`java.util.Optional` type, producing uncompilable `isEmpty()`
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 70/100
Línea de trabajo
Empieza en OptionalNotPresentToIsEmpty.java, especialmente con el MethodMatcher y la plantilla de reescritura a los que se hace referencia en las líneas 46 y 56. Reproduce la transformación con com.bazaarvoice.jolt.common.Optional y, después, añade una prueba de regresión que muestre que los receptores no resueltos o que no pertenecen al JDK permanecen sin cambios y que java.util.Optional se sigue reescribiendo correctamente.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- Java
- Estrellas
- 156
- Forks
- 129
- Merge medio
- 3 d 8 h
- PR fusionados (30 d)
- 14
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de openrewrite/rewrite-migrate-java
-
bug
Dificultad 4/5 3-5 días Aptitud para principiantes 68/100
openrewrite/rewrite-migrate-java#1246 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 70/100
openrewrite/rewrite-migrate-java#1228 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 32/100
openrewrite/rewrite-migrate-java#1227 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 4/5 3-5 días Aptitud para principiantes 50/100
openrewrite/rewrite-migrate-java#1119 · 5 comentarios ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
openrewrite/rewrite-migrate-java#1069 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de openrewrite/rewrite-migrate-java
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
geonetwork/geonetwork#227 ·
Los mantenedores suelen responder en 3 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Netcracker/qubership-testing-platform-tdm3#138 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
synthetichealth/synthea#1726 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
bisq-network/bisq#8097 ·
Los mantenedores suelen responder en 1 día
-
area/frontend good first issue kind/cooldown
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día