Case class creation, default parameters don't work
gregakespret opened this issue · comments
scala> import net.jcazevedo.moultingyaml._
import net.jcazevedo.moultingyaml._
scala> import net.jcazevedo.moultingyaml.DefaultYamlProtocol._ // if you don't supply your own protocol
import net.jcazevedo.moultingyaml.DefaultYamlProtocol._
scala> implicit val fooFormat = yamlFormat2(Foo)
fooFormat: net.jcazevedo.moultingyaml.YamlFormat[Foo] = net.jcazevedo.moultingyaml.ProductFormats$$anon$22@4d3fa7b5
scala> "bar: test".parseYaml.convertTo[Foo]
net.jcazevedo.moultingyaml.package$DeserializationException: YamlObject is missing required member 'baz'
at net.jcazevedo.moultingyaml.package$.deserializationError(package.scala:23)
at net.jcazevedo.moultingyaml.ProductFormats$class.readField(ProductFormats.scala:1079)
at net.jcazevedo.moultingyaml.DefaultYamlProtocol$.readField(DefaultYamlProtocol.scala:13)
at net.jcazevedo.moultingyaml.ProductFormats$$anon$22.read(ProductFormats.scala:200)
at net.jcazevedo.moultingyaml.ProductFormats$$anon$22.read(ProductFormats.scala:189)
at net.jcazevedo.moultingyaml.YamlValue.convertTo(YamlValue.scala:10)
at .<init>(<console>:17)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)
at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568)
at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:760)
at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:805)
at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:717)
at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:581)
at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:588)
at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:591)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:882)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:837)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:837)
at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:837)
at scala.tools.nsc.interpreter.ILoop.main(ILoop.scala:904)
at xsbt.ConsoleInterface.run(ConsoleInterface.scala:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:102)
at sbt.compiler.AnalyzingCompiler.console(AnalyzingCompiler.scala:77)
at sbt.Console.sbt$Console$$console0$1(Console.scala:23)
at sbt.Console$$anonfun$apply$2$$anonfun$apply$1.apply$mcV$sp(Console.scala:24)
at sbt.Console$$anonfun$apply$2$$anonfun$apply$1.apply(Console.scala:24)
at sbt.Console$$anonfun$apply$2$$anonfun$apply$1.apply(Console.scala:24)
at sbt.Logger$$anon$4.apply(Logger.scala:90)
at sbt.TrapExit$App.run(TrapExit.scala:244)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.NoSuchElementException: key not found: YamlString(baz)
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:58)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:58)
at net.jcazevedo.moultingyaml.ProductFormats$class.readField(ProductFormats.scala:1076)
... 44 more
Is there any workaround to this? When case class has default parameters, user still needs to define those in YAML.
Unfortunately that is currently not supported via the yamlFormatX
helpers. The best workaround for this is to define your own YamlFormat
(see this section for details) which handles the missing values in the YAML document properly.
However, this is something I'd like to add to MoultingYAML in the future, so I'll leave this issue open for the time being.
Found a solution to this, if you're still interested in extending this -
class WithOptionalLongId[T](baseFormatter:YamlFormat[T]) extends YamlFormat[T]{
import YamlSupport.yamlObjectToMergeable
def write(r:T) = baseFormatter.write(r)
def read(yaml:YamlValue) = {
baseFormatter.read(yaml.asYamlObject().mergeAfter(Map("id" -> 0L)))
}
}
(where the "mergeAfter" is just gluing some extra values)which allows for e.g.
implicit val MyClassFormat: YamlFormat[MyClass] = new WithOptionalLongId[User](yamlFormat8(MyClass.apply))