Search code examples
scalaannotationsxstream

XStream annotation not working in scala


I try to use XStream in scala, but it looks like the annotation in XSteam is not working in scala. In the following code, only @XStreamAlias work, I also attach one sample output, could anyone help this ?

@XStreamAlias("posts")
case class Posts(
  @XStreamAsAttribute tag: String,
  @XStreamAsAttribute total: String,
  @XStreamAsAttribute user: String,
  @XStreamImplicit(itemFieldName="post") posts: JList[Post])

@XStreamAlias("post")
case class Post(
  @XStreamAsAttribute description: String,
  @XStreamAsAttribute extended: String,
  @XStreamAsAttribute hash: String,
  @XStreamAsAttribute href: String,
  @XStreamAsAttribute shared: String,
  @XStreamAsAttribute tag: String,
  @XStreamAsAttribute time: String)


<posts>
  <tag>a</tag>
  <total>b</total>
  <user>c</user>
  <posts>
    <post>
      <description></description>
      <extended></extended>
      <hash></hash>
      <href></href>
      <shared></shared>
      <tag></tag>
      <time></time>
    </post>
  </posts>
</posts>

Solution

  • It looks like java annotations do not play well with Scala. :-) You'd have to rely on setting this with plain old method syntax. See below for a code snippet that I knocked up looking at their API documentation.

    import com.thoughtworks.xstream.annotations._
    import com.thoughtworks.xstream.XStream
    import java.util.{ ArrayList => JList }
    
    class Posts(
      val tag: String,
      val total: String,
      val user: String,
      val post: JList[Post])
    
    class Post(
      val description: String,
      val extended: String,
      val hash: String,
      val href: String,
      val shared: String,
      val tag: String,
      val time: String)
    
    object Main extends App {
      val xst = new XStream();
      val pp = new JList[Post]
    
      val rstv = new Post("a", "b", "c", "d", "e", "f", "g")
      pp.add(rstv)
      val postClazz = classOf[Post]
      val postsClazz = classOf[Posts]
      val pstv = new Posts("p", "q", "r", pp)
    
      xst.useAttributeFor(postsClazz, "tag")
      xst.useAttributeFor(postsClazz, "total")
      xst.useAttributeFor(postsClazz, "user")
    
      xst.useAttributeFor(postClazz, "description")
      xst.useAttributeFor(postClazz, "extended")
      xst.useAttributeFor(postClazz, "hash")
      xst.useAttributeFor(postClazz, "href")
      xst.useAttributeFor(postClazz, "shared")
      xst.useAttributeFor(postClazz, "tag")
      xst.useAttributeFor(postClazz, "time")
      val foo = xst.toXML(pstv)
      println(foo)
    }
    

    Note that all classes must have fields set up to be looked up by XStream. With this code, I got the below output:

    <Posts tag="p" total="q" user="r">
      <post>
        <Post description="a" extended="b" hash="c" href="d" shared="e" tag="f" time
    ="g"/>
      </post>
    </Posts>
    

    Hope this helps.

    EDIT: To expand on what I said above, annotations such as @XStreamAlias et al, were completely stripped from compiled bytecode. This can be seen by running javap or scalap on those compiled classes. This led me to conclude that java annotations were not treated on par with scala annotations(Though, ideally it should be - Feel free to chime in if I made any mistake). Would be glad to learn something. :-)