Skip to content

Commit

Permalink
Replace usages of org.apache.commons.lang.StringEscapeUtils with Gu…
Browse files Browse the repository at this point in the history
…ava (#9094)
  • Loading branch information
basil committed Mar 30, 2024
1 parent 47306c2 commit 9882ec6
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.util.SourceCodeEscapers;
import org.apache.commons.io.output.ProxyWriter;
import org.apache.commons.lang.StringEscapeUtils;
import org.kohsuke.stapler.framework.io.WriterOutputStream;

/**
Expand Down Expand Up @@ -122,7 +122,7 @@ public ConsoleAnnotator<T> annotate(T context, MarkupText text) {
}
} catch (IOException | ClassNotFoundException e) {
// if we failed to resurrect an annotation, ignore it.
LOGGER.log(Level.FINE, "Failed to resurrect annotation from \"" + StringEscapeUtils.escapeJava(new String(in, next, rest, Charset.defaultCharset())) + "\"", e);
LOGGER.log(Level.FINE, "Failed to resurrect annotation from \"" + SourceCodeEscapers.javaCharEscaper().escape(new String(in, next, rest, Charset.defaultCharset())) + "\"", e);
}

int bytesUsed = rest - b.available(); // bytes consumed by annotations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringEscapeUtils;
import jenkins.util.SourceCodeEscapers;

/**
* Filters out console notes.
Expand Down Expand Up @@ -73,7 +73,7 @@ protected void eol(byte[] in, int sz) throws IOException {
try {
ConsoleNote.skip(new DataInputStream(b));
} catch (IOException x) {
LOGGER.log(Level.FINE, "Failed to skip annotation from \"" + StringEscapeUtils.escapeJava(new String(in, next, rest, Charset.defaultCharset())) + "\"", x);
LOGGER.log(Level.FINE, "Failed to skip annotation from \"" + SourceCodeEscapers.javaCharEscaper().escape(new String(in, next, rest, Charset.defaultCharset())) + "\"", x);
}

int bytesUsed = rest - b.available(); // bytes consumed by annotations
Expand Down
51 changes: 51 additions & 0 deletions core/src/main/java/jenkins/util/SourceCodeEscapers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package jenkins.util;

import com.google.common.escape.ArrayBasedCharEscaper;
import com.google.common.escape.CharEscaper;
import com.google.common.escape.Escaper;
import java.util.Map;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

@Restricted(NoExternalUse.class)
public final class SourceCodeEscapers {

// Suppress default constructor for noninstantiability
private SourceCodeEscapers() {
throw new AssertionError();
}

private static final Map<Character, String> REPLACEMENTS = Map.of(
'\b', "\\b",
'\f', "\\f",
'\n', "\\n",
'\r', "\\r",
'\t', "\\t",
'\"', "\\\"",
'\\', "\\\\");

private static final char PRINTABLE_ASCII_MIN = 0x20;

private static final char PRINTABLE_ASCII_MAX = 0x7E;

private static final CharEscaper JAVA_CHAR_ESCAPER = new JavaCharEscaper();

/**
* Returns an {@link Escaper} instance that escapes special characters in a string so it can
* safely be included in either a Java character literal or string literal.
*/
public static CharEscaper javaCharEscaper() {
return JAVA_CHAR_ESCAPER;
}

private static class JavaCharEscaper extends ArrayBasedCharEscaper {
JavaCharEscaper() {
super(REPLACEMENTS, PRINTABLE_ASCII_MIN, PRINTABLE_ASCII_MAX);
}

@Override
protected char[] escapeUnsafe(char c) {
return String.format("\\u%04X", (int) c).toCharArray();
}
}
}
42 changes: 42 additions & 0 deletions core/src/test/java/jenkins/util/SourceCodeEscapersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package jenkins.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

import org.junit.Test;

public class SourceCodeEscapersTest {

@Test
public void testJavaCharEscaper() {
assertThrows(NullPointerException.class, () -> SourceCodeEscapers.javaCharEscaper()
.escape(null));
assertEquals("", SourceCodeEscapers.javaCharEscaper().escape(""));

assertEquals("foo", SourceCodeEscapers.javaCharEscaper().escape("foo"));
assertEquals("\\t", SourceCodeEscapers.javaCharEscaper().escape("\t"));
assertEquals("\\\\", SourceCodeEscapers.javaCharEscaper().escape("\\"));
assertEquals("'", SourceCodeEscapers.javaCharEscaper().escape("'"));
assertEquals("\\\\\\b\\t\\r", SourceCodeEscapers.javaCharEscaper().escape("\\\b\t\r"));
assertEquals("\\u1234", SourceCodeEscapers.javaCharEscaper().escape("\u1234"));
assertEquals("\\u0234", SourceCodeEscapers.javaCharEscaper().escape("\u0234"));
assertEquals("\\u00EF", SourceCodeEscapers.javaCharEscaper().escape("\u00ef"));
assertEquals("\\u0001", SourceCodeEscapers.javaCharEscaper().escape("\u0001"));
assertEquals("\\uABCD", SourceCodeEscapers.javaCharEscaper().escape("\uabcd"));

assertEquals(
"He didn't say, \\\"stop!\\\"",
SourceCodeEscapers.javaCharEscaper().escape("He didn't say, \"stop!\""));
assertEquals(
"This space is non-breaking:\\u00A0",
SourceCodeEscapers.javaCharEscaper().escape("This space is non-breaking:\u00a0"));
assertEquals(
"\\uABCD\\u1234\\u012C", SourceCodeEscapers.javaCharEscaper().escape("\uABCD\u1234\u012C"));
assertEquals(
"\\uD83D\\uDC80\\uD83D\\uDD14",
SourceCodeEscapers.javaCharEscaper().escape("\ud83d\udc80\ud83d\udd14"));
assertEquals(
"String with a slash (/) in it",
SourceCodeEscapers.javaCharEscaper().escape("String with a slash (/) in it"));
}
}

0 comments on commit 9882ec6

Please sign in to comment.