Repository: gwtproject/gwt (2024-12-10T19:09:05Z)

Issue:
Make string.split implement Java8 semantics
Originally reported on Google Code with ID 8913

```

Found in GWT Release (e.g. 2.4.0, 2.5.1, trunk):

N/A

Encountered on OS / Browser (e.g. WinXP, IE9, FF10):

N/A

Detailed description (please be as specific as possible):

String.split has different semantics in Java 8 (@see StringTest.testSplit_emptyExpr)

Shortest code snippet which demonstrates issue (please indicate where
actual result differs from expected result):



Workaround if you have one:



Links to relevant GWT Developer Forum posts:



Link to patch posted at http://gwt-review.googlesource.com


```

Reported by `rluble@google.com` on 2014-09-23 17:52:11



Discussion:
Reported by `rluble@google.com` on 2014-09-25 00:32:05
- **Labels added**: java8




Patch:
diff --git a/user/super/com/google/gwt/emul/java/lang/String.java b/user/super/com/google/gwt/emul/java/lang/String.java
index 693f53bdc7..42af2f1fe5 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -647,10 +647,22 @@ public String[] split(String regex, int maxMatch) {
       // subgroup handling
       NativeRegExp.Match matchObj = compiled.exec(trail);
       if (matchObj == null || trail == "" || (count == (maxMatch - 1) && maxMatch > 0)) {
+        // At the end of the string, or we have performed the maximum number of matches,
+        // record the remaining string and break
         out[count] = trail;
         break;
       } else {
         int matchIndex = matchObj.getIndex();
+
+        if (lastTrail == null && matchIndex == 0 && matchObj.asArray()[0].length() == 0) {
+          // As of Java 8, we should discard the first zero-length match if it is the beginning of
+          // the string. Do not increment the count, and do not add to the output array.
+          trail = trail.substring(matchIndex + matchObj.asArray()[0].length(), trail.length());
+          compiled.lastIndex = 0;
+          lastTrail = trail;
+          continue;
+        }
+
         out[count] = trail.substring(0, matchIndex);
         trail = trail.substring(matchIndex + matchObj.asArray()[0].length(), trail.length());
         // Force the compiled pattern to reset internal state


Test patch:
diff --git a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
index fc58bdcbde..80763a0b4f 100644
--- a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.emultest.java.lang;
 
 import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.testing.TestUtils;
 
 import java.util.Locale;
 
@@ -245,15 +244,30 @@ public void testSplit() {
         "b", "", ":and:f"});
     compareList("0:", "boo:and:foo".split(":", 0), new String[] {
         "boo", "and", "foo"});
-  }
+    // issue 2742
+    compareList("issue2742", new String[] {}, "/".split("/", 0));
+
+    // Splitting an empty string should result in an array containing a single
+    // empty string.
+    String[] s = "".split(",");
+    assertTrue(s != null);
+    assertTrue(s.length == 1);
+    assertTrue(s[0] != null);
+    assertTrue(s[0].length() == 0);
+
+    s = "abcada".split("a");
+    assertTrue(s != null);
+    assertEquals(3, s.length);
+    assertEquals("", s[0]);
+    assertEquals("bc", s[1]);
+    assertEquals("d", s[2]);  }
 
   public void testSplit_emptyExpr() {
-    // TODO(rluble):  implement JDK8 string.split semantics and fix test.
-    // See issue 8913.
-    String[] expected = (TestUtils.getJdkVersion() > 7) ?
-        new String[] {"a", "b", "c", "x", "x", "d", "e", "x", "f", "x"} :
-        new String[] {"", "a", "b", "c", "x", "x", "d", "e", "x", "f", "x"};
+    String[] expected = new String[] {"a", "b", "c", "x", "x", "d", "e", "x", "f", "x"};
     compareList("emptyRegexSplit", expected, "abcxxdexfx".split(""));
+
+    String[] arr = ",".split(",");
+    assertEquals(0, arr.length);
   }
 
   public void testStartsWith() {
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringTest.java b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
index ea12fee74c..c1c436e4b3 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
@@ -781,23 +781,30 @@ public void testSplit() {
 
     // Splitting an empty string should result in an array containing a single
     // empty string.
-    String[] s = "".split(",");
+    String[] s = hideFromCompiler("").split(",");
     assertTrue(s != null);
     assertTrue(s.length == 1);
     assertTrue(s[0] != null);
     assertTrue(s[0].length() == 0);
+
+    s = hideFromCompiler("abcada").split("a");
+    assertTrue(s != null);
+    assertEquals(3, s.length);
+    assertEquals("", s[0]);
+    assertEquals("bc", s[1]);
+    assertEquals("d", s[2]);
   }
 
   public void testSplit_emptyExpr() {
-    // TODO(rluble):  implement JDK8 string.split semantics and fix test.
-    String[] expected = (TestUtils.getJdkVersion() > 7) ?
-        new String[] {"a", "b", "c", "x", "x", "d", "e", "x", "f", "x"} :
-        new String[] {"", "a", "b", "c", "x", "x", "d", "e", "x", "f", "x"};
-    compareList("emptyRegexSplit", expected, "abcxxdexfx".split(""));
+    String[] expected = new String[] {"a", "b", "c", "x", "x", "d", "e", "x", "f", "x"};
+    compareList("emptyRegexSplit", expected, hideFromCompiler("abcxxdexfx").split(""));
+
+    String[] arr = hideFromCompiler(",").split(",");
+    assertEquals(0, arr.length);
   }
 
   public void testStartsWith() {
-    String haystack = "abcdefghi";
+    String haystack = hideFromCompiler("abcdefghi");
     assertTrue(haystack.startsWith("abc"));
     assertTrue(haystack.startsWith("bc", 1));
     assertTrue(haystack.startsWith(haystack));