eed3si9n / scalaxb

scalaxb is an XML data binding tool for Scala.
http://scalaxb.org/
MIT License
335 stars 154 forks source link

DataRecord[Any] fails to round trip #108

Closed deanhiller closed 12 years ago

deanhiller commented 12 years ago

steps

  def datarecordTest {
    val scope = scalaxb.toScope(Some("xs") -> "http://www.w3.org/2001/XMLSchema",
      Some("xsi") -> "http://www.w3.org/2001/XMLSchema-instance")
    val subject = <core:gln xmlns:core="urn:epcglobal:hls:1">0111222123458</core:gln>
    val r = scalaxb.fromXML[DataRecord[Any]](subject)
    val document = scalaxb.toXML[scalaxb.DataRecord[Any]](r, r.namespace, r.key, scope, true)
    document.toString match {
      case """<core:gln xmlns:core="urn:epcglobal:hls:1">0111222123458</core:gln>""" =>
      case x => error("match failed: " + x)
    }
  }

problem

[error] (run-main) java.lang.RuntimeException: match failed: <Some(core):gln xmlns:core="urn:epcglobal:hls:1">0111222123458</Some(core):gln>

expectation

it works.


I ran into 3 more bugs. Our most critical one is the attached test case below is failing

Bug 2 I worked around which required I delete the default namespace(I had xmlns:ghx="http://ghx.com/tnt" xmlns="http://ghx.com/tnt" which should be allowed but didn't work)

Bug 3 was that scalaxb does not fail when I sent <ghx:Something><ContextParm1/><ghx:Something> when ContextParm1 belongs to the epcis namespace the it should fail and force the user to send <ghx:Something><epcis:ContextParm1/><ghx:Something>....and I can't remember but I think when I sent it the epcis:ContextParm1, it did not read it in nor did it fail and just left it like it was not there or something. (anyways, the below test case is what we are currently blocked on...I don't think it is our code but I could be wrong). thanks, Dean

  @Test def testEventSequence() {

     val commissionXml = <epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1"
                                              xmlns:core="urn:epcglobal:hls:1"
        schemaVersion="1" creationDate="2010-04-01T14:11:23Z">
        <EPCISBody>
          <EventList>
            <ObjectEvent>
              <eventTime>2010-04-01T08:00:01.001-06:00</eventTime>
              <eventTimeZoneOffset>-06:00</eventTimeZoneOffset>
              <epcList>
                <epc>urn:epc:id:sgtin:0111222.999888.001</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.002</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.003</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.004</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.005</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.006</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.007</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.008</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.009</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.010</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.011</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.012</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.013</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.014</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.015</epc>
              </epcList>
              <action>ADD</action>
              <bizStep>urn:epcglobal:bizstep:commissioning</bizStep>
              <disposition>urn:epcglobal:disp:active</disposition>
              <readPoint>
                <id>urn:epc:id:sgln:0111222.12345.40</id>
                <core:gln>0111222123458</core:gln>
              </readPoint>
              <bizLocation>
                <id>urn:epc:id:sgln:0111222.12345.10</id>
                <core:gln>0111222123458</core:gln>
              </bizLocation>
            </ObjectEvent>
          </EventList>
        </EPCISBody>
      </epcis:EPCISDocument>

    val fixedScope = toScope(
    Some("core") -> "urn:epcglobal:hls:1",
    Some("epcis") -> "urn:epcglobal:epcis:xsd:1",
    Some("xs") -> "http://www.w3.org/2001/XMLSchema",
    Some("xsi") -> "http://www.w3.org/2001/XMLSchema-instance")

    def toXML3(event: EPCISDocumentType): NodeSeq = {
      toXML[EPCISDocumentType](event, Some("urn:epcglobal:epcis:xsd:1"), Some("EPCISDocument"), fixedScope)
    }

    def toXML2(event: EPCISEventType): NodeSeq = {
      toXML[EPCISEventType](event, Some("urn:epcglobal:epcis:xsd:1"), Some("EventObject"), fixedScope)
    }
    val xmlObj = fromXML[EPCISDocumentType](commissionXml)
    val evtList = xmlObj.EPCISBody.EventList.get
    val evtListType = evtList.eventlisttypeoption
    val head = evtListType.head
    val evt = head.value
    val evtType = evt.asInstanceOf[EPCISEventType]
    val xmlNodeSeq = toXML2(evtType)
    val xmlStr = xmlNodeSeq.toString
    val strippedXmlStr = EventDao.fixForBugInScalaXb(xmlStr)

    val retNodeSeq = XML.loadString(strippedXmlStr)
    val retObj = fromXML[EPCISEventType](retNodeSeq)
    val event = translateToDataRec(retObj)
    val theEvtList = Some(EventListType(event))
    val body = EPCISBodyType(theEvtList, None, Nil, Map[String, scalaxb.DataRecord[Any]]())
    val eventDoc = EPCISDocumentType(None, body, None, Nil, 1, retObj.eventTime, Map[String, scalaxb.DataRecord[Any]]())

    val xml = toXML[EPCISDocumentType](eventDoc, Some("urn:epcglobal:epcis:xsd:1"), Some("EPCISDocument"), NewTntAPIFactory.defaultScope)
    info("xml ="+xml)

  }
eed3si9n commented 12 years ago

I can't use the code because it's missing some stuff:

[error] main.scala:75: not found: value EventDao
[error]     val strippedXmlStr = EventDao.fixForBugInScalaXb(xmlStr)
[error]                          ^
[error] main.scala:79: not found: value translateToDataRec
[error]     val event = translateToDataRec(retObj)
[error]                 ^
[error] main.scala:84: not found: value NewTntAPIFactory
[error]     val xml = toXML[EPCISDocumentType](eventDoc, Some("urn:epcglobal:epcis:xsd:1"), Some("EPCISDocument"), NewTntAPIFactory.defaultScope)
[error]
deanhiller commented 12 years ago

I found I have another test case break and I noticed something as I think it is the same reason as the unit test case above. I see it bug 1 marshal fine after unmarshalling but when built up manually marshalling fails with the exception. There are the two objects I marshalled(the toString on the scalaxb generated object that is)...notice for some reason, one of them is a WrappedArray(the one that doesn't work) while the other is a List. The second one here fails to marshal to xml....

EPCISDocumentType(
None,
EPCISBodyType(Some(EventListType(List(DataRecord(ObjectEvent,ObjectEventType(2010-04-01T08:00:01.001-06:00,None,-06:00,None,EPCListType(List(EPC(urn:epc:id:sgtin:0111222.999888.913), EPC(urn:epc:id:sgtin:0111222.999888.695))),ADD,Some(urn:epcglobal:bizstep:commissioning),Some(urn:epcglobal:disp:active),Some(ReadPointType(urn:epc:id:sgln:0111222.00008,None,List())),Some(BusinessLocationType(urn:epc:id:sgln:0111222.00001.0,None,List())),None,None,List(DataRecord({urn:epcglobal:hls:1}lot,<core:lot xmlns:epcis="urn:epcglobal:epcis:xsd:1" xmlns:core="urn:epcglobal:hls:1">xxx-100</core:lot>), DataRecord({urn:epcglobal:hls:1}expirationDate,<core:expirationDate xmlns:epcis="urn:epcglobal:epcis:xsd:1" xmlns:core="urn:epcglobal:hls:1">2011-12-31T12:00:01.001-06:00</core:expirationDate>), DataRecord({urn:epcglobal:hls:1}productCode,<core:productCode xmlns:epcis="urn:epcglobal:epcis:xsd:1" xmlns:core="urn:epcglobal:hls:1">urn:epc:idpat:sgtin:0111222.999888.*</core:productCode>)),Map()))))),None,List(),Map()),None,List(),1,2010-04-01T14:11:23Z,Map())

EPCISDocumentType(
None,
EPCISBodyType(Some(EventListType(WrappedArray(DataRecord(ObjectEventType(2011-11-04T09:04:07.859-06:00,None,-6:00,None,EPCListType(List(EPC(urn:epc:id:sgtin:0111222.999888.913), EPC(urn:epc:id:sgtin:0111222.999888.695))),OBSERVE,Some(urn:epcglobal:bizstep:other),Some(urn:epcglobal:disp:non_sellable_recalled),None,None,None,None,List(),Map()))))),None,List(),Map()),None,List(),1,2011-11-04T09:04:07.859-06:00,Map())
eed3si9n commented 12 years ago

I am kind of confused about the three bugs you're mentioning. (avoid using #, because on github it would actually link to the gh issue number). If there are three distinct bugs, could you file them separately?

eed3si9n commented 12 years ago

The fact that one is List and the other is WrappedArray should not matter since I mostly require them to be Seq. The WrappedArray likely came from the internal structure of the way scala's xml holds child nodes. More interesting difference, however, is the fact that the first DataRecord is aware of the element name,

DataRecord(ObjectEvent,ObjectEventType(...))

while the second one is not.

DataRecord(ObjectEventType(...))
deanhiller commented 12 years ago

Here is the test case(sorry!) stripped out the fix as we are upgraded and don't need that method now and added the other missing method...

  @Test def testEventSequence() {

     val commissionXml = <epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1"
                                              xmlns:core="urn:epcglobal:hls:1"
        schemaVersion="1" creationDate="2010-04-01T14:11:23Z">
        <EPCISBody>
          <EventList>
            <ObjectEvent>
              <eventTime>2010-04-01T08:00:01.001-06:00</eventTime>
              <eventTimeZoneOffset>-06:00</eventTimeZoneOffset>
              <epcList>
                <epc>urn:epc:id:sgtin:0111222.999888.001</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.002</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.003</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.004</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.005</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.006</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.007</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.008</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.009</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.010</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.011</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.012</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.013</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.014</epc>
                <epc>urn:epc:id:sgtin:0111222.999888.015</epc>
              </epcList>
              <action>ADD</action>
              <bizStep>urn:epcglobal:bizstep:commissioning</bizStep>
              <disposition>urn:epcglobal:disp:active</disposition>
              <readPoint>
                <id>urn:epc:id:sgln:0111222.12345.40</id>
                <core:gln>0111222123458</core:gln>
              </readPoint>
              <bizLocation>
                <id>urn:epc:id:sgln:0111222.12345.10</id>
                <core:gln>0111222123458</core:gln>
              </bizLocation>
            </ObjectEvent>
          </EventList>
        </EPCISBody>
      </epcis:EPCISDocument>

    def toXML2(event: EPCISEventType): NodeSeq = {
      toXML[EPCISEventType](event, Some("urn:epcglobal:epcis:xsd:1"), Some("EventObject"), defaultScope)
    }
    val xmlObj = fromXML[EPCISDocumentType](commissionXml)
    val evtList = xmlObj.EPCISBody.EventList.get
    val evtListType = evtList.eventlisttypeoption
    val head = evtListType.head
    val evt = head.value
    val evtType = evt.asInstanceOf[EPCISEventType]
    val xmlNodeSeq = toXML2(evtType)
    val xmlStr = xmlNodeSeq.toString

    val retNodeSeq = XML.loadString(xmlStr)
    val retObj = fromXML[EPCISEventType](retNodeSeq)

    def translateToDataRec(evt:EPCISEventType) : DataRecord[Any] = {
      evt match {
        case e : ObjectEventType => DataRecord[ObjectEventType](e)
        case e : AggregationEventType => DataRecord[AggregationEventType](e)
        case e : TransactionEventType => DataRecord[TransactionEventType](e)
        case e : QuantityEventType => DataRecord[QuantityEventType](e)
      }
    }

    val event = translateToDataRec(retObj)
    val theEvtList = Some(EventListType(event))
    val body = EPCISBodyType(theEvtList, None, Nil, Map[String, scalaxb.DataRecord[Any]]())
    val eventDoc = EPCISDocumentType(None, body, None, Nil, 1, retObj.eventTime, Map[String, scalaxb.DataRecord[Any]]())

    val xml = toXML[EPCISDocumentType](eventDoc, Some("urn:epcglobal:epcis:xsd:1"), Some("EPCISDocument"), NewTntAPIFactory.defaultScope)
    info("xml ="+xml)
  }
eed3si9n commented 12 years ago

At least one part of the problem is that DataRecord[Any] is failing to round trip. See the updated description.

eed3si9n commented 12 years ago

This was a bug introduced during the recent node scope merging changes. With this fixed, and translateToDataRec fixed as follows, the test code now runs:

    def translateToDataRec(evt:EPCISEventType) : DataRecord[Any] = {
      evt match {
        case e : ObjectEventType => DataRecord[ObjectEventType](None, Some("ObjectEvent"), e)
        case e : AggregationEventType => DataRecord[AggregationEventType](None, Some("AggregationEvent"), e)
        case e : TransactionEventType => DataRecord[TransactionEventType](None, Some("TransactionEvent"), e)
        case e : QuantityEventType => DataRecord[QuantityEventType](None, Some("QuantityEvent"), e)
      }
    }

See https://github.com/eed3si9n/scalaxb-epcis-sample