使用JAXB,处理“嵌套”资源表示列表的标准方法(例如<products><product>X</product><product>Y</product></products>
)是创建一个包装器对象,在Java中可能看起来像这样(借用Jhopify ):
@XmlType(name = "")
@XmlRootElement(name = "products")
public class ProductList {
List<Product> products = new ArrayList<Product>();
@XmlElement(name = "product", required = true)
public List<Product> getProducts() { return products; }
public void setProducts(List<Product> products) { this.products = products; }
}
但是,在将其转换为Scala时,我正在努力确定要使用哪些集合对象。在Mostly Blather blog上执行此操作有一个很好的介绍性帖子,它使用Scala Iterable与JCollection进行隐式转换(使用JavaConversions)。
这非常适合将JAXB类编组为XML,但遗憾的是,在解组时会在每次UnsupportedOperationException
尝试时抛出add
。基于此Scala documentation page的最后一段,看起来这是因为Java不区分其类型中的可变集合和不可变集合。
为了处理解组,我尝试了一种专门使用可变对象的替代方法:
@XmlType(name = "")
@XmlRootElement(name = "products")
class ProductList {
private var products: Buffer[Product] = new ArrayBuffer[Product]
@XmlElement(name = "product", required = true)
def getProducts: JList[Product] = products
def setProducts(products: JList[Product]) {
this.products = products
}
}
但不幸的是,通过这种方法,解组给了我一个例外:
java.lang.NoSuchMethodError: ProductList.getProducts()Ljava/util/Collection;
编辑根据Travis的要求,这是我的解组代码:
val jaxbContext = JAXBContext.newInstance(ProductList.getClass())
val unmarshaller = jaxbContext.createUnmarshaller()
val root = unmarshaller.unmarshal(new StreamSource(new StringReader(responseString)), ProductList.getClass())
val r = root.getValue().asInstanceOf[ProductList]
val representations = r.getProducts.asScala.toList // Uses scalaj
所以我有点难过......我也看了scalaj's available conversions,但没有明显跳出来。任何帮助非常感谢!
答案 0 :(得分:4)
你能发布你的解组代码吗?我已经用Scala中的JAXB做了类似的事情,你看起来像应该工作。这是一个完整的工作示例:
import javax.xml.bind.annotation._
class Thing {
@scala.reflect.BeanProperty var name: String = _
}
@XmlRootElement(name = "things")
class Things {
import scala.collection.JavaConversions._
import scala.collection.mutable.Buffer
private var things: Buffer[Thing] = Buffer[Thing]()
@XmlElement(name = "thing", required = true)
def getThings: java.util.List[Thing] = this.things
def setThings(things: java.util.List[Thing]) {
this.things = things
}
}
我也会在Scala中编写测试代码,但它在Java中的工作方式相同。
object Things {
import java.io.StringReader
import java.io.StringWriter
import javax.xml.bind.JAXBContext
def main(args: Array[String]) {
val thing1 = new Thing
val thing2 = new Thing
thing1.setName("Thing 1")
thing2.setName("Thing 2")
val list: java.util.List[Thing] = new java.util.ArrayList[Thing]
list.add(thing1)
list.add(thing2)
val things = new Things
things.setThings(list)
val context = JAXBContext.newInstance(classOf[Things])
val writer = new StringWriter
context.createMarshaller.marshal(things, writer)
println(writer.toString)
val readThings = context.createUnmarshaller().unmarshal(
new StringReader(writer.toString)
).asInstanceOf[Things]
println("Size: " + readThings.getThings.size)
println("Name of first: " + readThings.getThings.get(0).getName)
}
}
这会编译并生成您期望的输出。