3

I'm busy trying to answer this question myself: Scala Play 2.4.x handling extended characters through anorm (MySQL) to 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 tend to re-write most things that work on Strings into a wrapped StringBuilder call in case I'm already building something with another StringBuilder in which case I can just pass that StringBuilder as a param - if not then works as a normal String by calling the first function.

You would think this is all fine 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 "declaring" the first parameter needed to be a string:

stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i)))

and yet the compiler didn't take the hint that the overloaded method with a java.util.Locale would do the trick.

I moved the code to a less cluttered class thinking perhaps it was an import doing this but no such luck.

So the question is how does one disable Implicit's that are not of one's choosing?

OR

How does one satisfy the compiler's need to know what you really want here?

Community
  • 1
  • 1
Techmag
  • 1,383
  • 13
  • 24

4 Answers4

0

Apparently this compiles:

    stringBuilder.append(String.format("&#x%x;": String, Character.codePointAt(input, i).toString))

However I believe this might defeat the entire purpose of calling format in the first place if the toString gets hold of things first.

So my original questions still stands...

Techmag
  • 1,383
  • 13
  • 24
0

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 an Int and when we toString it (which appears to be OK in this context) then the String.format needs a tweak to handle a string substitution.

I think I'm going to redo this with Scala style String manipulation and see what happens

 s"""&#x${Character.codePointAt(input, i)};"""
Techmag
  • 1,383
  • 13
  • 24
  • I say *might* as apparently we've pissed off Mandrill with repeated testing and their servers are blocking test attempts right now. (sigh). One more ticket raised... – Techmag Jul 15 '15 at 16:24
0

This apparently DOES 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
    }
  }

It does NOT however answer my original question regarding implicits.

Techmag
  • 1,383
  • 13
  • 24
0

Your problem has nothing to do with implicits* and everything to do with the fact that a Scala Int is not an Object. The error message is telling you the truth: String.format has two overloads and your parameter list doesn't match either of them.

Try using Int.box(Character.codePointAt(input, i)) to make your parameter into an Object.

*Okay, it has a little to do with implicits, in that an Int can be implicitly converted to an Integer, but that won't be applied to convert an Int to Object.

Joe Pallas
  • 2,105
  • 1
  • 14
  • 17
  • I though Scala had no primitives? As Int has methods (like toString etc) doesn't that indicate it is an Object? My question could be mute in that I found a way to get the code to compile by changing it but I think the premise of the question stands - how do you explicitly turn OFF an Implicit you do not want applied within a particular scope? – Techmag Jul 15 '15 at 20:09
  • 1
    In Scala, everything is an object, but not everything is a reference, and only references are Java Objects. Check out http://docs.scala-lang.org/tutorials/tour/unified-types.html for the big picture. – Joe Pallas Jul 16 '15 at 20:25
  • 1
    The very first line of that link states: In contrast to Java, all values in Scala are objects (including numerical values and functions). Do you have docs specifically on the difference between a reference versus an object (in this specific context)? – Techmag Jul 17 '15 at 12:46
  • 1
    The most definitive documentation is the [Scala language specification](http://www.scala-lang.org/docu/files/ScalaReference.pdf), which says in section 12.1, "The subclass AnyRef represents all values which are represented as objects in the underlying host system." Thus, for Scala hosted on the JVM, instances of classes that do not inherit from AnyRef are not Java objects. In this context, that means that a Scala Int can't be implicitly converted to a Java Object. – Joe Pallas Jul 18 '15 at 23:03