How can I disable a specific Implicit in Scala that prevents code from being compiled due to overloaded methods?
I'm trying to answer this question myself: Scala Play 2.4.x wide character handling via anorm (MySQL) in Java Mail
and I came across this possible solution: https://objectpartners.com/2013/04/24/html-encoding-utf-8-characters/
So, I decided to rewrite the sample in Scala:
def htmlEncode(input: String) = htmlEncode_sb(input).toString
def htmlEncode_sb(input: String, stringBuilder: StringBuilder = new StringBuilder()) = {
for ((c, i) <- input.zipWithIndex) {
if (CharUtils.isAscii(c)) {
// Encode common HTML equivalent characters
stringBuilder.append(StringEscapeUtils.escapeHtml4(c.toString()))
} else {
// Why isn't this done in escapeHtml4()?
stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i)))
}
}
stringBuilder
}
}
FYI: I usually rewrite most things that work with Strings into a wrapped call to StringBuilder in case I am already creating something with another StringBuilder, in which case I can just pass this StringBuilder as a parameter if it doesn't work like normal string by calling the first function.
You might think that everything is ok and dandy, however the Scala compiler has this to say:
[info] Compiling 1 Scala source to /SomeOne/SomePath/SomeProject/target/scala-2.11/classes...
[error] /SomeOne/SomePath/SomeProject/TKEmailAgent.scala:278: overloaded method value format with alternatives:
[error] (x$1: java.util.Locale,x$2: String,x$3: Object*)String <and>
[error] (x$1: String,x$2: Object*)String
[error] cannot be applied to (String, Int)
[error] stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i)))
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
Note that I even tried to "declare" the first parameter, which must be a string:
stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i)))
and yet the compiler didn't figure out that the overloaded method with java.util.Locale would do the trick.
I moved the code into a less cluttered class, thinking it might have been an import, but it wasn't.
So the question is, how to disable the implicit ones that are not selected?
OR
How to satisfy the compiler need to know what you really want here?
source to share
Apparently this compiles:
stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i).toString))
However, I believe it can lead to a primarily victory in the purpose of assigning a format if toString gets hold of things first.
So my original questions are still standing ...
source to share
And this might actually work:
def htmlEncode(input: String) = htmlEncode_sb(input).toString
def htmlEncode_sb(input: String, stringBuilder: StringBuilder = new StringBuilder()) = {
for ((c, i) <- input.zipWithIndex) {
if (CharUtils.isAscii(c)) {
// Encode common HTML equivalent characters
stringBuilder.append(StringEscapeUtils.escapeHtml4(c.toString()))
} else {
// Why isn't this done in escapeHtml4()?
stringBuilder.append(String.format("""&#x%s;""": String, Character.codePointAt(input, i).toString))
}
}
stringBuilder
}
}
It turns out that CodePointAt returns Int and when we toString it (which looks OK in this context), String.format needs to be configured to handle string substitution.
I think I'll rewrite this with the Scala String style and see what happens
s"""&#x${Character.codePointAt(input, i)};"""
source to share
It seems to work!
def htmlEncode(input: String) = htmlEncode_sb(input).toString
def htmlEncode_sb(input: String, stringBuilder: StringBuilder = new StringBuilder()) = {
stringBuilder.synchronized {
for ((c, i) <- input.zipWithIndex) {
if (CharUtils.isAscii(c)) {
// Encode common HTML equivalent characters
stringBuilder.append(StringEscapeUtils.escapeHtml4(c.toString()))
} else {
// Why isn't this done in escapeHtml4()?
stringBuilder.append(s"""&#${Character.codePointAt(input, i)};""")
}
}
stringBuilder
}
}
However, it doesn't answer my original no-show question.
source to share
Your problem has nothing to do with implicits * and anything to do with the fact that Scala is Int
not Object
. The error message tells you the truth: it String.format
has two overloads, and the parameter list doesn't match either of them.
Try using Int.box(Character.codePointAt(input, i))
to make your parameter to Object
.
* Ok, it has little to do with implicits as it Int
can be implicitly converted to Integer
, but that won't apply to converting Int
to Object
.
source to share