I'm trying to convert objects of type Option[T]
to XML using Xstream in Scala. I have a case class like this:
case class MyModel(promos: Option[Promos])
If the option is Some(Promo)
, I'd like it to render
<MyModel>
<Promos>
<promoField1>value</promoField1>
<promoField2>value</promoField2>
</Promos>
</MyModel>
If the option is None
, I'd like it to render
<MyModel>
<Promos/>
</MyModel>
So far in my solution, I have registered a converter:
xstream.registerConverter(new OptionConverter(xstream.getMapper))
I then have a custom converter that looks like this:
private [xml] class OptionConverter(_mapper: Mapper) extends AbstractCollectionConverter(_mapper: Mapper) {
override def marshal(source: scala.Any, writer: HierarchicalStreamWriter, context: MarshallingContext): Unit = {
val opt = source.asInstanceOf[Option[_]]
for (value <- opt) {
writeItem(value, context, writer)
}
}
override def unmarshal(reader: HierarchicalStreamReader, context: UnmarshallingContext): AnyRef = {
throw new UnsupportedOperationException
}
override def canConvert(clazz: Class[_]): Boolean = {
clazz.isAssignableFrom(classOf[Some[_]]) || clazz.isAssignableFrom(None.getClass)
}
}
The None
works fine, but Some(promo)
outputs like this:
<Promos>
<com.mymodel.Promos>
<promoField1>value</promoField1>
<promoField2>value</promoField2>
</com.mymodel.Promos>
</Promos>
The problem is, Promos is being output for my Option/Some
field, "com.mymodel.Promos" is then being output for the nested value within Some
. Is there a way to flatten is for Some(value)
?
I managed to make the Option
Converter to marshal objects to XML. (The reading part is not required for me, so I left that unimplemented)
import com.thoughtworks.xstream.converters.{MarshallingContext, UnmarshallingContext}
import com.thoughtworks.xstream.io.{HierarchicalStreamReader, HierarchicalStreamWriter}
private [xml] sealed class OptionConverter extends com.thoughtworks.xstream.converters.Converter {
override def marshal(source: scala.Any, writer: HierarchicalStreamWriter, context: MarshallingContext): Unit = {
val opt = source.asInstanceOf[Option[_]]
for (value <- opt) {
context.convertAnother(opt.get)
}
}
override def unmarshal(reader: HierarchicalStreamReader, context: UnmarshallingContext): AnyRef = {
throw new UnsupportedOperationException
}
override def canConvert(clazz: Class[_]): Boolean = {
clazz.isAssignableFrom(classOf[Some[_]]) || clazz.isAssignableFrom(None.getClass)
}
}