av9ash/GitBugs huggingface dataset:
Bug: Update json4s for Scala 2.13
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 26/Jul/20 00:24
Affects Version/s: 3.1.0

We need to upgrade to avoid the following error.
{code}
  Cause: java.lang.NoSuchMethodException: scala.collection.immutable.Seq$.apply(scala.collection.Seq)
  at java.lang.Class.getMethod(Class.java:1786)
  at org.json4s.Extraction$CollectionBuilder.reflMethod$Method1(Extraction.scala:476)
  at org.json4s.Extraction$CollectionBuilder.$anonfun$result$9(Extraction.scala:476)
  at org.json4s.Extraction$CollectionBuilder.mkCollection(Extraction.scala:437)
  at org.json4s.Extraction$CollectionBuilder.result(Extraction.scala:476)
  at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:392)
  at org.json4s.Extraction$.$anonfun$customOrElse$1(Extraction.scala:658)
  at scala.PartialFunction.applyOrElse(PartialFunction.scala:187)
  at scala.PartialFunction.applyOrElse$(PartialFunction.scala:186)
  at scala.PartialFunction$$anon$1.applyOrElse(PartialFunction.scala:339)
{code}
Bug: Allow plugins to inject rules into AQE query stage preparation
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 24/Jul/20 14:51
Affects Version/s: 3.0.0

Provide a generic mechanism for plugins to inject rules into the AQE "query prep" stage that happens before query stage creation.

this goes along with https://issues.apache.org/jira/browse/SPARK-32332 where the current AQE implementation doesn't allow for users to properly extend it for columnar processing. 

The issue here is that we create new query stages but we do not have access to the parent plan of the new query stage so certain things can not be determined because you have to know what the parent did.  With this change it would allow you to add TAGs to be able to figure out what is going on.
Bug: Implement TableCatalog for JDBC
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 20/Jul/20 19:48
Affects Version/s: 3.1.0

Implement the TableCatalog interface, in particular:
- list tables
- table exists
- drop table
- rename table
- Optionally, alter table
- Optionally, load table
- Optionally, create table
Bug: "Resolved attribute(s) XXX missing" after dudup conflict references
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 20/Jul/20 14:48
Affects Version/s: 2.2.2

{code:java}
// case class Person(id: Int, name: String, age: Int)

sql("SELECT name, avg(age) as avg_age FROM person GROUP BY name").createOrReplaceTempView("person_a")
sql("SELECT p1.name, p2.avg_age FROM person p1 JOIN person_a p2 ON p1.name = p2.name").createOrReplaceTempView("person_b")
sql("SELECT * FROM person_a UNION SELECT * FROM person_b")   .createOrReplaceTempView("person_c")
sql("SELECT p1.name, p2.avg_age FROM person_c p1 JOIN person_c p2 ON p1.name = p2.name").show
{code}
error:
{code:java}
[info]   Failed to analyze query: org.apache.spark.sql.AnalysisException: Resolved attribute(s) avg_age#235 missing from name#233,avg_age#231 in operator !Project [name#233, avg_age#235]. Attribute(s) with the same name appear in the operation: avg_age. Please check if the right attribute(s) are used.;;
...{code}
Bug: Investigate commonizing Columnar and Row data transformations 
Status: Open | Priority: Major | Resolution: 
Created: 16/Jul/20 17:59
Affects Version/s: 3.0.0

We introduced more Columnar Support with SPARK-27396.

With that we recognized that there is code that is doing very similar transformations from ColumnarBatch or Arrow into InternalRow and vice versa.  For instance: [https://github.com/apache/spark/blob/a4382f7fe1c36a51c64f460c6cb91e93470e0825/sql/core/src/main/scala/org/apache/spark/sql/execution/Columnar.scala#L56-L58]

[https://github.com/apache/spark/blob/a4382f7fe1c36a51c64f460c6cb91e93470e0825/sql/core/src/main/scala/org/apache/spark/sql/execution/Columnar.scala#L389]

We should investigate if we can commonize that code.

We are also looking at making the internal caching serialization pluggable to allow for different cache implementations. ([https://github.com/apache/spark/pull/29067]). 

It was recently brought up that we should investigate if using the data source v2 api makes sense and is feasible for some of these transformations to allow it to be easily extended.
Bug: ./bin/spark-sql got error with reading hive metastore
Status: Closed | Priority: Major | Resolution: Fixed
Created: 02/Jul/20 07:47
Affects Version/s: 3.0.0

1. Fist of all, I built Spark3.0.0 from source with below command.
{quote}{{./build/mvn -Pyarn -Phive -Phive-thriftserver -Dskip Tests clean package}}
{quote}
2. I set the ${SPARK_HOME}/conf/spark-defaults.conf as below.
{quote}spark.sql.hive.metastore.version    2.1.1

spark.sql.hive.metastore.jars    {color:#ff0000}maven{color}
{quote}
3. There is no problem to run "${SPARK_HOME}/bin/spark-sql"

4. For production environment, I copied all downloaded jar files from maven to ${SPARK_HOME}/lib/

5. I changed ${SPARK_HOME}/conf/spark-defaluts.conf as below.
{quote}spark.sql.hive.metastore.jars   {color:#ff0000}${SPARK_HOME}/lib/{color}
{quote}
6. Then I got error running command ./bin/spark-sql as below.
{quote}Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hive/ql/metadata/HiveException
{quote}
I found out that HiveException class is in the hive-exec-XXX.jar...

Spark 3.0.0 was built with hive 2.3.7 by default, and I could find "hive-exec-2.3.7-core.jar" after I finished build. And I could find hive-exec-2.1.1.jar downloaded from maven when I use "spark.sql.hive.metastore.jars maven" in the spark-defaults.conf.

 

I thought that there are some conflict between hive 2.1.1 and hive 2.3.7 when I set the {color:#7a869a}spark.sql.hive.metastore.jars   ${SPARK_HOME}/lib/.{color}
Bug: Track whether the worker is also being decommissioned along with an executor
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 08/Jul/20 00:50
Affects Version/s: 3.1.0

When an executor is decommissioned, we would like to know if its shuffle data is truly going to be lost. In the case of external shuffle service, this means knowing that the worker (or the node that the executor is on) is also going to be lost. 

 

( I don't think we need to worry about disaggregated remote shuffle storage at present since those are only used in a couple of web companies – but when there is remote shuffle then yes the shuffle won't be lost with a decommissioned executor )

 

We know for sure that a worker is being decommissioned when the Master is asked to decommission a worker. In case of other schedulers:
 * Yarn support for decommissioning isn't implemented yet. But the idea would be for Yarn preeemption to not mark that the worker is being lost, but machine level decommissioning (like for kernel upgrades) to do mark such.
 * K8s isn't quite working with external shuffle service as yet, so when the executor is lost, the worker isn't quite lost with it.
Bug: BROADCAST hint makes a weird message that "column can't be resolved" (it was OK in Spark 2.4)
Status: Closed | Priority: Major | Resolution: Duplicate
Created: 17/Jul/20 15:12
Affects Version/s: 3.0.0

The bug is very easily reproduced: run the following same code in Spark 2.4.3. and in 3.0.0.

The SQL parser will raise an invalid error message with 3.0.0, although everything seems to be OK with the SQL statement and it works fine in Spark 2.4.3
{code:python}
import pandas as pd

pdf_sales = pd.DataFrame([(1, 10), (2, 20)], columns=["BuyerID", "Qty"])
pdf_buyers = pd.DataFrame([(1, "John"), (2, "Jack")], columns=["BuyerID", "BuyerName"])

df_sales = spark.createDataFrame(pdf_sales)
df_buyers = spark.createDataFrame(pdf_buyers)

df_sales.createOrReplaceTempView("df_sales")
df_buyers.createOrReplaceTempView("df_buyers")

spark.sql("""
    with b as (
        select /*+ BROADCAST(df_buyers) */
            BuyerID, BuyerName 
        from df_buyers
    )
    select 
        b.BuyerID,
        b.BuyerName,
        s.Qty
    from df_sales s
        inner join b on s.BuyerID =  b.BuyerID
""").toPandas()
{code}

The (wrong) error message:
---------------------------------------------------------------------------
AnalysisException                         Traceback (most recent call last)
<ipython-input-4-8dfe318a59ee> in <module>
     22     from df_sales s
     23         inner join b on s.BuyerID =  b.BuyerID
---> 24 """).toPandas()

/opt/spark-3.0.0-bin-without-hadoop/python/pyspark/sql/session.py in sql(self, sqlQuery)
    644         [Row(f1=1, f2=u'row1'), Row(f1=2, f2=u'row2'), Row(f1=3, f2=u'row3')]
    645         """
--> 646         return DataFrame(self._jsparkSession.sql(sqlQuery), self._wrapped)
    647 
    648     @since(2.0)

/opt/spark-3.0.0-bin-without-hadoop/python/lib/py4j-0.10.9-src.zip/py4j/java_gateway.py in __call__(self, *args)
   1303         answer = self.gateway_client.send_command(command)
   1304         return_value = get_return_value(
-> 1305             answer, self.gateway_client, self.target_id, self.name)
   1306 
   1307         for temp_arg in temp_args:

/opt/spark-3.0.0-bin-without-hadoop/python/pyspark/sql/utils.py in deco(*a, **kw)
    135                 # Hide where the exception came from that shows a non-Pythonic
    136                 # JVM exception message.
--> 137                 raise_from(converted)
    138             else:
    139                 raise

/opt/spark-3.0.0-bin-without-hadoop/python/pyspark/sql/utils.py in raise_from(e)

AnalysisException: cannot resolve '`s.BuyerID`' given input columns: [s.BuyerID, b.BuyerID, b.BuyerName, s.Qty]; line 12 pos 24;
'Project ['b.BuyerID, 'b.BuyerName, 's.Qty]
+- 'Join Inner, ('s.BuyerID = 'b.BuyerID)
   :- SubqueryAlias s
   :  +- SubqueryAlias df_sales
   :     +- LogicalRDD [BuyerID#23L, Qty#24L], false
   +- SubqueryAlias b
      +- Project [BuyerID#27L, BuyerName#28]
         +- SubqueryAlias df_buyers
            +- LogicalRDD [BuyerID#27L, BuyerName#28], false
Bug: Fix java.lang.IndexOutOfBoundsException: No group -1
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 20/Jul/20 06:27
Affects Version/s: 3.0.1

The current implement of regexp_extract will throws a unprocessed exception show below:

SELECT regexp_extract('1a 2b 14m', 'd+' -1)


{code:java}
java.lang.IndexOutOfBoundsException: No group -1
java.util.regex.Matcher.group(Matcher.java:538)
org.apache.spark.sql.catalyst.expressions.RegExpExtract.nullSafeEval(regexpExpressions.scala:455)
org.apache.spark.sql.catalyst.expressions.TernaryExpression.eval(Expression.scala:704)
org.apache.spark.sql.catalyst.optimizer.ConstantFolding$$anonfun$apply$1$$anonfun$applyOrElse$1.applyOrElse(expressions.scala:52)
org.apache.spark.sql.catalyst.optimizer.ConstantFolding$$anonfun$apply$1$$anonfun$applyOrElse$1.applyOrElse(expressions.scala:45)
{code}
Bug: CaseInsensitiveMap should be deterministic for addition
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 21/Jul/20 00:39
Affects Version/s: 2.1.3

{code}
import org.apache.spark.sql.catalyst.util.CaseInsensitiveMap
var m = CaseInsensitiveMap(Map.empty[String, String])
Seq(("paTh", "1"), ("PATH", "2"), ("Path", "3"), ("patH", "4"), ("path", "5")).foreach { kv =>
  m = (m + kv).asInstanceOf[CaseInsensitiveMap[String]]
  println(m.get("path"))
}

Some(1)
Some(2)
Some(3)
Some(4)
Some(1)
{code}
Bug: Partially push down disjunctive predicates through Join/Partitions
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 14/Jul/20 10:04
Affects Version/s: 3.1.0

In https://github.com/apache/spark/pull/28733, CNF conversion is used to push down disjunctive predicates through join.

It's a good improvement, however, 
1. converting all the predicates in CNF can lead to a very long result, even with grouping functions over expressions.
2.the non-recursive is not easy for understanding.

Essentially, we just need to traverse predicate and extract the convertible sub-predicates like what we did in https://github.com/apache/spark/pull/24598. There is no need to maintain the CNF result set.
Bug: temp view not working after upgrading from 2.3.3 to 2.4.5
Status: Resolved | Priority: Major | Resolution: Won't Fix
Created: 19/Jul/20 16:43
Affects Version/s: 2.4.5

After upgrading from 2.3.3 to spark 2.4.5. the temp view seems not working . Please correct me if i miss sth. Thanks!

Steps to reproduce:

```

from pyspark.sql import SparkSession
 from pyspark.sql import Row
 spark=SparkSession\
 .builder \
 .appName('scenary_address_1') \
 .enableHiveSupport() \
 .getOrCreate()
 address_tok_result_df=spark.createDataFrame([Row(a=1,b='难',c=80),Row(a=2,b='v',c=81)])
 print("create dataframe finished")
 address_tok_result_df.createOrReplaceTempView("scenery_address_test1")
 print(spark.read.table('scenery_address_test1').dtypes)
 spark.sql("select * from scenery_address_test1").show()

```

 

In spark2.3.3  I can easily gey the following result:

```

create dataframe finished
 [('a', 'bigint'), ('b', 'string'), ('c', 'bigint')]
 +-----+-++---
|a|b|c|

+-----+-++---
|1|难|80|
|2|v|81|

+-----+-+—+

```

 

But in 2.4.5. i can only get,but without result showing out:

create dataframe finished
 [('a', 'bigint'), ('b', 'string'), ('c', 'bigint')]
Bug: Remove redundant sorts before repartition nodes
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 10/Jul/20 22:34
Affects Version/s: 3.1.0

I think our {{EliminateSorts}} rule can be extended further to remove sorts before repartition, repartitionByExpression and coalesce nodes. Independently of whether we do a shuffle or not, each repartition operation will change the ordering and distribution of data.

That's why we should be able to rewrite {{Repartition -> Sort -> Scan}} as {{Repartition -> Scan}}.
Bug: R version is too old on Jenkins k8s PRB
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 15/Jul/20 18:10
Affects Version/s: 3.1.0

I'm seeing a consistent failure indicating the R version is out of date - [https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/30513/console]
Bug: ThriftCLIService.GetOperationStatus should include exception's stack trace to the error message
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 01/Jul/20 07:09
Affects Version/s: 3.0.1

In https://issues.apache.org/jira/browse/SPARK-29283, we only show the error message of root cause to end-users through JDBC client. In some cases, it erases the straightaway messages that we intentionally make to help them for better understanding.

We should do as Hive does in https://issues.apache.org/jira/browse/HIVE-14368
Bug: SET TIME ZONE standard sql command support
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 10/Jul/20 11:00
Affects Version/s: 3.1.0



{code:java}
Function
Set the current default time zone displacement for the current SQL-session.
Format
<set local time zone statement> ::=
SET TIME ZONE <set time zone value>
<set time zone value> ::=
<interval value expression>
| LOCAL

Syntax Rules
1) The declared type of the <interval value expression> immediately contained in the <set time zone value> shall be INTERVAL HOUR TO MINUTE.
{code}
Bug: JSON predicate pushdown for nested fields
Status: Open | Priority: Major | Resolution: 
Created: 15/Jul/20 17:57
Affects Version/s: 3.1.0

SPARK-30648 should support filters pushdown to JSON datasource but it supports only filters that refer to top-level fields. The ticket aims to support nested fields as well. See the needed changes: https://github.com/apache/spark/pull/27366#discussion_r443340603
Bug: ValueError when loading a PipelineModel on a personal computer
Status: Resolved | Priority: Major | Resolution: Invalid
Created: 01/Jul/20 08:25
Affects Version/s: 2.4.5

I have a PipelineModel saved on my computer that I can't load using {{PipelineModel.load(path)}}.

When I launch my code in a Databricks cluster, it works. {{path}} is the path to my model saved on DBFS, accessible via a mount point: {{path = "/dbfs/path/to/my/model}}.

However on my machine, calling {{PipelineModel.load("C:\\Users\\path\\to\\my\\model")}} throws a {{ValueError("RDD is empty")}}.

Here is how the model is saved on my computer:
{code:title=pipeline.txt}
\---model
    +---metadata
    |       part-00000
    |       _SUCCESS
    |
    \---stages
        +---0_CountVectorizer_b92625354bf7
        |   +---data
        |   |       part-00000-tid-9156766819779394023-5cf6aecb-8959-48b3-be24-65bfa0543465-62-1-c000.snappy.parquet
        |   |       _committed_9156766819779394023
        |   |       _started_9156766819779394023
        |   |       _SUCCESS
        |   |
        |   \---metadata
        |           part-00000
        |           _SUCCESS
        |
        \---1_LinearSVC_108fa01daf43
            +---data
            |       part-00000-tid-4403060754466700849-27841dd9-de88-4015-9dfa-7854c2a15f15-65-1-c000.snappy.parquet
            |       _committed_4403060754466700849
            |       _started_4403060754466700849
            |       _SUCCESS
            |
            \---metadata
                    part-00000
                    _SUCCESS
{code}


(I just downloaded the model from my DataLake to my computer)

How can I load this model when running my code in local?
Bug: 'Spark driver' stays running even though 'spark application' has FAILED
Status: Open | Priority: Major | Resolution: 
Created: 06/Jul/20 14:45
Affects Version/s: 2.4.6

App failed in 6 minutes, driver has been stuck for > 8 hours. I would expect driver to fail if app fails.

 

Thread dump from jstack (on the driver pid) attached (j1.out)

Last part of stdout driver log attached (full log is 23MB, stderr log just has launch command)

Last part of app logs attached

 

Can see that "org.apache.spark.util.ShutdownHookManager - Shutdown hook called"  line never appears in the driver log after "org.apache.spark.SparkContext - Successfully stopped SparkContext"

 

Using spark 2.4.6 with spark standalone mode. spark-submit to REST API (port 6066) in cluster mode was used. Other drivers/apps have worked fine with this setup, just this one getting stuck. My cluster has 1 EC2 dedicated as spark master and 1 Spot EC2 dedicated as spark worker. They can auto heal/spot terminate at any time. From checking aws logs: the worker was terminated at 01:53:38

 

I think you can replicate this by tearing down worker machine while app is running. You might have to try several times.

 

Similar to https://issues.apache.org/jira/browse/SPARK-24617 i raised before!
Bug: Avoid expanding too many CNF predicates in partition pruning
Status: In Progress | Priority: Major | Resolution: 
Created: 12/Jul/20 13:23
Affects Version/s: 3.1.0

After https://github.com/apache/spark/pull/28805, the pushed down predicates for partition pruning can be very long.
For example, the following partition filter:

{code:java}
(p0 = '1' AND p1 = '1') OR (p0 = '2' AND p1 = '2') OR (p0 = '3' AND p1 = '3') OR (p0 = '4' AND p1 = '4') OR (p0 = '5' AND p1 = '5') OR (p0 = '6' AND p1 = '6') OR (p0 = '7' AND p1 = '7') OR (p0 = '8' AND p1 = '8') OR (p0 = '9' AND p1 = '9') OR (p0 = '10' AND p1 = '10') OR (p0 = '11' AND p1 = '11') OR (p0 = '12' AND p1 = '12') OR (p0 = '13' AND p1 = '13') OR (p0 = '14' AND p1 = '14') OR (p0 = '15' AND p1 = '15') OR (p0 = '16' AND p1 = '16') OR (p0 = '17' AND p1 = '17') OR (p0 = '18' AND p1 = '18') OR (p0 = '19' AND p1 = '19') OR (p0 = '20' AND p1 = '20')
{code}

will be converted into a 130K long query in Hive metastore, and there will be error:

{code:java}
javax.jdo.JDOException: Exception thrown when executing query : SELECT DISTINCT 'org.apache.hadoop.hive.metastore.model.MPartition' AS NUCLEUS_TYPE,A0.CREATE_TIME,A0.LAST_ACCESS_TIME,A0.PART_NAME,A0.PART_ID,A0.PART_NAME AS NUCORDER0 FROM PARTITIONS A0 LEFT OUTER JOIN TBLS B0 ON A0.TBL_ID = B0.TBL_ID LEFT OUTER JOIN DBS C0 ON B0.DB_ID = C0.DB_ID WHERE B0.TBL_NAME = ? AND C0."NAME" = ? AND ((((((A0.PART_NAME LIKE '%/p1=1' ESCAPE '\' ) OR (A0.PART_NAME LIKE '%/p1=2' ESCAPE '\' )) OR (A0.PART_NAME LIKE '%/p1=3' ESCAPE '\' )) OR ((A0.PART_NAME LIKE '%/p1=4' ESCAPE '\' ) O ...
{code}

To avoid it:
1. We should push down the convertible original queries as they are, instead of converting all predicates into CNF
2. We can skip grouping expression so that we can stop the CNF conversion when the predicates becoming too long.
Bug: IllegalArgumentException: MultilayerPerceptronClassifier_... parameter solver given invalid value auto
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 08/Jul/20 15:57
Affects Version/s: 3.0.0

I believe I have discovered a bug when loading MultilayerPerceptronClassificationModel in spark 3.0.0, scala 2.1.2 which I have tested and can see is not there in at least Spark 2.4.3, Scala 2.11.  (I'm not sure if the Scala version is important).

 

I am using pyspark on a databricks cluster and importing the library  "from pyspark.ml.classification import MultilayerPerceptronClassificationModel"

 

When running model=MultilayerPerceptronClassificationModel.("load") and then model. transform (df) I get the following error: IllegalArgumentException: MultilayerPerceptronClassifier_8055d1368e78 parameter solver given invalid value auto.

 

 

This issue can be easily replicated by running the example given on the spark documents: [http://spark.apache.org/docs/latest/ml-classification-regression.html#multilayer-perceptron-classifier]

 

Then adding a save model, load model and transform statement as such:

 

*from* *pyspark.ml.classification* *import* MultilayerPerceptronClassifier

*from* *pyspark.ml.evaluation* *import* MulticlassClassificationEvaluator

 

_# Load training data_

data = spark.read.format("libsvm")\

    .load("data/mllib/sample_multiclass_classification_data.txt")

 

_# Split the data into train and test_

splits = data.randomSplit([0.6, 0.4], 1234)

train = splits[0]

test = splits[1]

 

_# specify layers for the neural network:_

_# input layer of size 4 (features), two intermediate of size 5 and 4_

_# and output of size 3 (classes)_

layers = [4, 5, 4, 3]

 

_# create the trainer and set its parameters_

trainer = MultilayerPerceptronClassifier(maxIter=100, layers=layers, blockSize=128, seed=1234)

 

_# train the model_

model = trainer.fit(train)

 

_# compute accuracy on the test set_

result = model.transform(test)

predictionAndLabels = result.select("prediction", "label")

evaluator = MulticlassClassificationEvaluator(metricName="accuracy")

*print*("Test set accuracy = " + str(evaluator.evaluate(predictionAndLabels)))

 

*from* *pyspark.ml.classification* *import* MultilayerPerceptronClassifier, MultilayerPerceptronClassificationModel

model.save(Save_location)

model2. MultilayerPerceptronClassificationModel.load(Save_location)

 

result_from_loaded = model2.transform(test)
Bug: Improve file path name normalisation at block resolution within the external shuffle service
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 01/Jul/20 13:30
Affects Version/s: 3.1.0

In the external shuffle service during the block resolution the file paths (for disk persisted RDD and for shuffle blocks) are normalized by a custom Spark code which uses an OS dependent regexp. This is a redundant code of the package-private JDK counterpart.
As the code not a perfect match even it could happen one method results in a bit different (but semantically equal) path. 

The reason of this redundant transformation is the interning of the normalized path to save some heap here which is only possible if both results in the same string.

Checking the JDK code I believe there is a better solution which is perfect match for the JDK code as it uses that package private method. Moreover based on some benchmarking even this new method seams to be more performant too.