1

I am trying to read a comma separated file in scala and convert that into list of Json object. The code is working if all the records are valid. How do i catch the exception for the records which are not valid in my function below. If a record is not valid it should throw and exception and continue reading the file. but in my case once an invalid record comes the application stops.

def parseFile(file: String): List[JsObject] = {

val bufferedSource = Source.fromFile(file)
try {
  bufferedSource.getLines().map(line => {
    val cols = line.split(",").map(_.trim)
    (Json.obj("Name" -> cols(0), "Media" -> cols(1), "Gender" -> cols(2), "Age" -> cols(3).toInt)) // Need to handle io exception here.
  }).toList
}

finally {
  bufferedSource.close()
  }
}
3
  • What do you mean by "throw an exception and continue reading the file"? If an exception is thrown, you can't keep going... Commented Aug 9, 2016 at 23:52
  • 1
    To throw an exception means to break out of the current execution, and return up the call stack until you find a handler for that exception. If you want to just handle an error locally, then either never throw an exception and just handle it with local code/method calls, or catch the exception locally. Commented Aug 10, 2016 at 0:00
  • maybe you should just do some validity checks for a line (Like cols.size >= x) or however you want to assure validity and otherwise skip the line or put it in a separate list and at least return a tuple with the "correct" json and the wrong lines. That way you're able to handle those lines or to inform the user. Another way to handle your problem in Scala it the either object you could return that and put your json in it or otherwise if errors occur the faulty lines. You should try to omit exceptions if not really needed because they are side-effects. Commented Aug 10, 2016 at 0:28

1 Answer 1

3

I think you may benefit from using Option (http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html) and the Try object (http://danielwestheide.com/blog/2012/12/26/the-neophytes-guide-to-scala-part-6-error-handling-with-try.html)

What you are doing here is stopping all work when an error happens (ie you throw to outside the map) a better option is to isolate the failure and return some object that we can filer out. Below is a quick implementation I made

package csv

import play.api.libs.json.{JsObject, Json}

import scala.io.Source
import scala.util.Try

object CsvParser extends App {

  //Because a bad row can either != 4 columns or the age can not be a int we want to return an option that will be ignored by our caller
  def toTuple(array : Array[String]): Option[(String, String, String, Int)] = {
    array match {
      //if our array has exactly 4 columns  
      case Array(name, media, gender, age) => Try((name, media, gender, age.toInt)).toOption
      // any other array size will be ignored
      case _ => None
    }
  }

  def toJson(line: String): Option[JsObject] = {
    val cols = line.split(",").map(_.trim)
    toTuple(cols) match {
      case Some((name: String, media: String, gender: String, age: Int)) => Some(Json.obj("Name" -> name, "Media" -> media, "Gender" -> gender, "Age" -> age))
      case _ => None
    }
  }

  def parseFile(file: String): List[JsObject] = {

    val bufferedSource = Source.fromFile(file)
    try { bufferedSource.getLines().map(toJson).toList.flatten } finally { bufferedSource.close() }

  }

  parseFile("my/csv/file/path")

}

The above code will ignore any rows where there not exactly 4 columns. It will also contain the NumberFormatException from .toInt.

The idea is to isolate the failure and pass back some type that the caller can either work with when the row was parsed...or ignore when a failure happened.

Sign up to request clarification or add additional context in comments.

2 Comments

Hello @Jono Thank you very much for the example and a very helpful reference, This was exactly i was looking for :)
You are welcome. I just noticed that I missed the try-finally. There seems to be some well knows issues with Scala Source. check back at my editted code. It seems to work for me and assures that the Source's InputStream is closed

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.