Какую правильную комбинацию Scala и Java-коллекции использовать с вложенным JAXB? - PullRequest
1 голос
/ 24 сентября 2011

Работа с 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 есть хорошая вступительная статья, в которой используется итерация Scala, неявно преобразуемая (с использованием JavaConversions) в JCollection и из нее.

Это прекрасно работает для маршалинга класса JAXB в XML, но, к сожалению, при демаршаллинге это выдает UnsupportedOperationException при каждой попытке add. На основании последнего абзаца на этой странице документации Scala похоже, что это происходит потому, что 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
  }
}

Но, к сожалению, при таком подходе unmarshalling дает мне исключение:

java.lang.NoSuchMethodError: ProductList.getProducts()Ljava/util/Collection;

Редактировать: в соответствии с запросом Трэвиса, вот мой код демаршаллинга:

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 , но ничего очевидного не выскакивает. Любая помощь высоко ценится!

1 Ответ

4 голосов
/ 25 сентября 2011

Не могли бы вы опубликовать свой код демаршаллинга?Я сделал что-то похожее с JAXB из Scala, и то, что у вас выглядит, выглядит так: должно работать.Вот полный рабочий пример:

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)
  }
}

Это компилирует и производит выводвы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...