6

I'm trying to create a multi-line String in Scala as below.

val errorReport: String =
    """
      |{
      |"errorName":"blah",
      |"moreError":"blah2",
      |"errorMessage":{
      |         "status": "bad",
      |         "message": "Unrecognized token 'noformatting': was expecting 'null', 'true', 'false' or NaN
 at [Source: (ByteArrayInputStream); line: 1, column: 25]"
      | }
      |}
      """
   .stripMargin

It's a nested JSON and it's not displaying properly when I print it. The message field inside errorMessage (which is the output of calling getMessage on an instance of a Throwable) is causing the issue because it looks like there is a newline right before

at [Source: ....

If I get rid of that line the JSON displays properly. Any ideas on how to properly format this are appreciated.

EDIT: The issue is with the newline character. So I think the question is more concisely - how to handle the newline within the triple quotes so that it's still recognized as a JSON?

EDIT 2: message is being set by a variable like so:

"message": "${ex.getMessage}"

where ex is a Throwable. An example of the contents of that getMessage call is provided above.

8
  • So, your question is about how to format your Scala code, not about JSON? Commented Apr 1, 2019 at 18:35
  • Yes, it's about what I need to do in Scala to be able to properly read this as a JSON. Commented Apr 1, 2019 at 18:42
  • Ok, then, is your question duplicate of this one? Commented Apr 1, 2019 at 19:10
  • 1
    have you seen the latest edit? Commented Apr 1, 2019 at 19:19
  • 1
    Just saw it and it worked! Thanks!! Ended up doing this: "message": "${ex.getMessage.replaceAll("\\n", " ")}" Commented Apr 1, 2019 at 19:25

1 Answer 1

5

Update 2023: I don't know why anyone would bother generating JSON manually in 2023. Just use some appropriate library that knows how to serialize stuff to JSON.


(original answer)

I assume that your question has nothing to do with JSON, and that you're simply asking how to create very wide strings without violating the horizontal 80-character limit in your Scala code. Fortunately, Scala's string literals have at least the following properties:

  • You can go from ordinary code to string-literal mode using quotes "..." and triple quotes """...""".
  • You can go from string-literal mode to ordinary code mode using ${...}
  • Free monoid over characters is reified as methods, that is, there is the + operation that concatenates string literals.
  • The whole construction can be made robust to whitespace and indentation using | and stripMargin.

All together, it allows you to write down arbitrary string literals without ever violating horizontal character limits, in a way that is robust w.r.t. indentation.

In this particular case, you want to make a line break in the ambient scala code without introducing a line break in your text. For this, you simply

  • exit the string-literal mode by closing """
  • insert concatenation operator + in code mode
  • make a line-break
  • indent however you want
  • re-enter the string-literal mode again by opening """

That is,

"""blah-""" +
"""blah"""

will create the string "blah-blah", without line break in the produced string.


Applied to your concrete problem:

val errorReport: String = (
    """{
      |  "errorName": "blah",
      |  "moreError": "blah2",
      |  "errorMessage": {
      |    "status": "bad",
      |    "message": "Unrecognized token 'noformatting'""" +
    """: was expecting 'null', 'true', 'false' or NaN at """ +
    """[Source: (ByteArrayInputStream); line: 1, column: 25]"
      |  }
      |}
      """
  ).stripMargin

Maybe a more readable option would be to construct the lengthy message separately from the neatly indented JSON, and then use string interpolation to combine the two components:

val errorReport: String = {
  val msg = 
    """Unrecognized token 'noformatting': """ +
    """was expecting 'null', 'true', 'false' or NaN at """ +
    """[Source: (ByteArrayInputStream); line: 1, column: 25]"""

    s"""{
      |  "errorName": "blah",
      |  "moreError": "blah2",
      |  "errorMessage": {
      |    "status": "bad",
      |    "message": "${msg}"
      |  }
      |}
      """
  }.stripMargin

If the message itself contains line breaks

Since JSON does not allow multiline string literals, you have to do something else:

  • To remove line breaks, use .replaceAll("\\n", "") or rather .replaceAll("\\n", " ")
  • To encode line breaks with the escape sequence \n, use .replaceAll("\\n", "\\\\n") (yes... backslashes...)
Sign up to request clarification or add additional context in comments.

3 Comments

The message field is being set via a variable: "message": "${ex.getMessage}" Where ex is a Throwable so I can't hardcode what the message will be. All I know is that it contains a newline somewhere and that's messing it up.
@covfefe And what do you want to do with the newline? Who is supposed to decide that? JSON does not allow line breaks in the middle of string literals.
Yes, JSON doesn't allow line breaks but I want to include it as part of the same field. Maybe by ignoring the line break altogether if that's possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.