Convert Seq [String] to case class by type

I wrote a parser that converts String to Seq [String], following some rules. It will be used in the library.

I am trying to convert this Seq [String] to the case class. The case class will be provided by the user (so there is no way to guess what it will be).

I thought of a shapeless library because it seems to implement good features and seems mature, but I have no idea how to proceed.

I found this question with an interesting answer , but I do not find how to convert it for my needs. In fact, the answer has only one type for parsing (String), and the library iterates inside the string itself. This probably requires profound changes in how this is done, and I don't know how to do it.

In addition, if possible, I want to make this process as simple as possible for the user of my library. Therefore, if possible, unlike the answer in the link above, the HList type will be guessed from the case class itself (however, according to my search, it seems that the compiler needs this information).

I am a little new to the type system and all these wonderful things, if someone can give me advice on how to do this, I would be very happy!

Yours faithfully

--- EDIT ---

As requested by ziggystar, here are some of the possible signatures:

//Let say we are just parsing a CSV. @onUserSide case class UserClass(i:Int, j:Int, s:String) val list = Seq("1,2,toto", "3,4,titi") // User transforms his case class to a function with something like: val f = UserClass.curried // The function created in 1/ is injected in the parser val parser = new Parser(f) // The Strings to convert to case classes are provided as an argument to the parse() method. val finalResult:Seq[UserClass] = parser.parse(list) // The transfomation is done in two steps inside the parse() method: // 1/ first we have: val list = Seq("1,2,toto", "3,4,titi") // 2/ then we have a call to internalParserImplementedSomewhereElse(list) // val parseResult is now equal to Seq(Seq("1", "2", "toto"), Seq("3","4", "titi")) // 3/ finally Shapeless do its magick trick and we have Seq(UserClass(1,2,"toto"), UserClass(3,4,"titi)) @insideTheLibrary class Parser[A](function:A) { //The internal parser takes each String provided through argument of the method and transforms each String to a Seq[String]. So the Seq[String] provided is changed to Seq[Seq[String]]. private def internalParserImplementedSomewhereElse(l:Seq[String]): Seq[Seq[String]] = { ... } /* * Class A and B are both related to the case class provided by the user: * - A is the type of the case class as a function, * - B is the type of the original case class (can be guessed from type A). */ private def convert2CaseClass[B](list:Seq[String]): B { //do something with Shapeless //I don't know what to put inside ??? } def parse(l:Seq[String]){ val parseResult:Seq[Seq[String]] = internalParserImplementedSomewhereElse(l:Seq[String]) val finalResult = result.map(convert2CaseClass) finalResult // it is a Seq[CaseClassProvidedByUser] } } 

Inside the library, some implicit ones will be available for converting String to the correct type, as Shapeless guesses (similar to what was suggested in the link above). Like string.toInt, string.ToDouble, etc.

Maybe there is another way to develop it. This is what I mean after playing with Shapeless for several hours.

+6
source share
2 answers

It uses a very simple library called product collections.

 import com.github.marklister.collections.io._ case class UserClass(i:Int, j:Int, s:String) val csv = Seq("1,2,toto", "3,4,titi").mkString("\n") csv: String = 1,2,toto 3,4,titi CsvParser(UserClass).parse(new java.io.StringReader(csv)) res28: Seq[UserClass] = List(UserClass(1,2,toto), UserClass(3,4,titi)) 

And for serialization in another way:

 scala> res28.csvIterator.toList res30: List[String] = List(1,2,"toto", 3,4,"titi") 

product collections are focused on csv and java.io.Reader, hence the pads above.

+1
source

This answer will not tell you how to do exactly what you want, but it will solve your problem. I think you are too complicated.

What do you want to do? It seems to me that you're just looking for a way to serialize and deserialize your case classes - i.e. convert your Scala objects to a common string format and a common string format back to Scala objects. Your serialization step at the moment is what you seem to have already defined, and you are asking how to perform deserialization.

There are several serialization / deserialization options available for Scala. You do not need to crack using Shapeless or Scalaz to do it yourself. Try a look at these solutions:

  • Java serialization / deserialization . Regular serialization / deserialization tools provided by the Java environment. Explicit casting is required and does not give you control over the serialization format, but it is built-in and does not require much work to implement.
  • JSON serialization: There are many libraries that provide JSON generation and parsing for Java. Take a look at play-json , spray-json and Argonaut , for example.
  • Scala Etching Library - A more general library for serialization / deserialization. Out of the box, it comes with some binary and some JSON formats, but you can create your own formats.

Of these solutions, at least play-json and Scala scale etching uses macros to generate serializers and deserializers for you at compile time. This means that they must be typical and effective.

0
source

All Articles