diff --git a/src/main/java/org/openrewrite/java/migrate/lang/UseTextBlocks.java b/src/main/java/org/openrewrite/java/migrate/lang/UseTextBlocks.java index 843aa5e72b..a6de613d71 100644 --- a/src/main/java/org/openrewrite/java/migrate/lang/UseTextBlocks.java +++ b/src/main/java/org/openrewrite/java/migrate/lang/UseTextBlocks.java @@ -247,7 +247,11 @@ private static boolean isRegularStringLiteral(Expression expr) { J.Literal l = (J.Literal) expr; return TypeUtils.isString(l.getType()) && l.getValueSource() != null && - !l.getValueSource().startsWith("\"\"\""); + !l.getValueSource().startsWith("\"\"\"") && + // Defend against literals whose value still looks like the source (e.g. parser failed to + // decode supplementary characters encoded as surrogate pairs); skipping prevents emitting + // a broken text block that drops or re-escapes content. + !l.getValueSource().equals(l.getValue()); } return false; } diff --git a/src/test/java/org/openrewrite/java/migrate/lang/UseTextBlocksTest.java b/src/test/java/org/openrewrite/java/migrate/lang/UseTextBlocksTest.java index 984fbfa08f..6d6345bd40 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/UseTextBlocksTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/UseTextBlocksTest.java @@ -995,6 +995,27 @@ class Test { ); } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/1110") + @Test + void supplementaryCharacterAsSurrogatePair() { + // The Java parser currently returns a corrupted value/valueSource for string literals containing + // supplementary characters encoded as surrogate pairs. Until that is fixed upstream, the recipe + // must bail out rather than emit a broken text block that drops or re-escapes content. + rewriteRun( + spec -> spec.recipe(new UseTextBlocks()), + java( + """ + class Test { + String json = + "{\\n" + + " \\"euro\\": 1,\\n" + + " \\"ligature\\": 2,\\n" + + " \\"\\ud834\\udd20\\": 3\\n" + + "}"; + }""", + src -> src.markers(javaVersion(17)))); + } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/555") @Test void textBlockTrailingEscape() {