Announcement Announcement Module
Collapse
No announcement yet.
StaxEventItemReader + Xstream unmarshaller => KO Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • StaxEventItemReader + Xstream unmarshaller => KO

    Dear all,

    I just have some practice with SPring documentation example on StaxEventItemReader and XStream unmarshalling
    cf doc 6.7.1 StaxEventItemReader
    It doesn't seem to work and i receive the following exception:

    Code:
    ava.lang.UnsupportedOperationException: XStreamMarshaller does not support unmarshalling using SAX XMLReaders
    	at org.springframework.oxm.xstream.XStreamMarshaller.unmarshalSaxReader(XStreamMarshaller.java:460)
    Below the bloc of code i've tested:
    Code:
    @SuppressWarnings("unchecked")
    	@Test
    	public void testStaxReader () throws Exception {
    		
    		StaxEventItemReader xmlStaxEventItemReader = new StaxEventItemReader();
    		Resource resource = new FileSystemResource("src/test/resources/data/input/spring.xml.customer.xml") ;
    
    		Map aliases = new HashMap();
    		aliases.put("customer","com.natixis.aws.customer.CustomerCredit");
    		XStreamMarshaller marshaller = new XStreamMarshaller();
    		marshaller.setAliases(aliases);
    		xmlStaxEventItemReader.setUnmarshaller(marshaller);
    		xmlStaxEventItemReader.setResource(resource);
    		xmlStaxEventItemReader.setFragmentRootElementName("customer");
    		xmlStaxEventItemReader.open(new ExecutionContext());
    
    		boolean hasNext = true;
    		CustomerCredit credit = null;
    
    		while (hasNext) {
    				credit = (CustomerCredit)xmlStaxEventItemReader.read();
    				if (credit == null) {
    				    hasNext = false;
    				}
    				else {
    				    System.out.println(credit);
    				}
    		}
    		xmlStaxEventItemReader.close();
    		
    	}
    Unfortunately, this code doesn't work because inside the read method, StaxEventItemReader initializes a Source of type org.springframework.xml.transform.StaxSource which implements SAXSource

    Code:
    protected T doRead() throws Exception {
    
    
    if (noInput) {
    
    return null;
    
    }
    
    
    T item = null;
    
    
    if (moveCursorToNextFragment(fragmentReader)) {
    
    fragmentReader.markStartFragment();
    
    
    @SuppressWarnings("unchecked")
    
    T mappedFragment = (T) unmarshaller.unmarshal(new StaxSource(fragmentReader));
    
    
    item = mappedFragment;
    
    fragmentReader.markFragmentProcessed();
    
    }
    
    
    return item;
    
    }
    and the XStreamMarshaller doesn't support this operation:

    Code:
    @Override
    
    protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
    
    throws XmlMappingException, IOException {
    
    
    throw new UnsupportedOperationException(
    
    "XStreamMarshaller does not support unmarshalling using SAX XMLReaders");
    
    }
    Any help would be very appreciated...
    Thanks in advance

  • #2
    I think there is some confusion here between SAX (not supported by XStream) and Stax (supported). There are several unit and integration tests that work just fine for StaxEventItemReader and XStream. So what is the problem exactly? Do you have a stack trace?

    Comment


    • #3
      Hello Dave,

      Thanks for your response.

      It's clear for me that Stax and SAX are different things but the org.springframework.xml.transform.StaxSource that StaxEventItemReader initializes during the doRead method implements itself SAXSource.

      Code:
      StaxEvent T mappedFragment = (T) unmarshaller.unmarshal(new StaxSource(fragmentReader));
      And the problem is that if you use XStreamMarshaller, this implementation (but not the others like JAXB2Marshaller) doesn't support unmarshalling with SAX resource.

      Stack: cf unmarshall method from XStreamMarshaller
      Code:
      ava.lang.UnsupportedOperationException: XStreamMarshaller does not support unmarshalling using SAX XMLReaders
      	at org.springframework.oxm.xstream.XStreamMarshaller.unmarshalSaxReader(XStreamMarshaller.java:460)
      So my question is: is it possible to use both StaxEventItemReader and XstreamMarshaller to unmarshall XML fragments to Java objects?
      As far as i tested, the response is no...

      Regards,

      Comment


      • #4
        There must be some funny business going on with your classpath or something because it works fine for everyone else. The StaxSource does extend SAXSource, but it has its own unmarshalStaxSource() method in the unmarshaller which should be the one that is picked.

        Comment


        • #5
          Dave,

          That's exactly the point.

          In the AbstractMarshaller from which extends the XStreamMarshaller, we have the following code:

          Code:
          public final Object unmarshal(Source source) throws IOException, XmlMappingException {
          		if (source instanceof DOMSource) {
          			return unmarshalDomSource((DOMSource) source);
          		}
          		else if (StaxUtils.isStaxSource(source)) {
          			return unmarshalStaxSource(source);
          		}
          		else if (source instanceof SAXSource) {
          			return unmarshalSaxSource((SAXSource) source);
          		}
          		else if (source instanceof StreamSource) {
          			return unmarshalStreamSource((StreamSource) source);
          		}
          		else {
          			throw new IllegalArgumentException("Unknown Source type: " + source.getClass());
          		}
          	}
          All the problem lies in that we don't pass in the unmarshalStaxSource(source) bloc - so StaxUtils.isStaxSource evaluated to false - but in the following one.

          That means that in my case StaxUtils.isStaxSource returns false but source instance of SAXSource returns true.

          If we look at the SaxUtils method there's the following test:
          Code:
          public static boolean isStaxSource(Source source) {
          		return (source instanceof StaxSource || (jaxp14Available && Jaxp14StaxHandler.isStaxSource(source)));
          	}
          the first statement source instanceof StaxSource returns false because our source is of type org.springframework.xml.transform.StaxSource and you check the type org.springframework.util.xml.StaxSource which are completely different ones.

          For me the error would not arise if you would change the code of the StaxReader from the following one:

          Code:
          @SuppressWarnings("unchecked")
          			T mappedFragment = (T) unmarshaller.unmarshal(new StaxSource(fragmentReader));
          to this one

          Code:
          @SuppressWarnings("unchecked")
          			T mappedFragment = (T) unmarshaller.unmarshal(StaxUtils.createStaxSource(fragmentReader));
          In this case, we would have the correct type initialiezd in the reader and we would call the unmarshalStaxSource from the XStreamMarshaller.

          Regards,

          Comment


          • #6
            Hello Dave,

            I found the source of the problem.

            I'm using Spring Batch 2.1.0.RELEASE with Spring 3.0.1.RELEASE with Jdk 1.5.

            Test 1
            When I use the following environment :
            . Spring Batch 2.1.0.RELEASE
            . Spring WS 1.5.9 (modules spring-xml and spring-oxm)
            . Spring 2.5.6
            Everything works fine.

            Test 2
            When I use the following environment :
            . Spring Batch 2.1.0.RELEASE
            . Spring 3.1.0.RELEASE
            . and WITHOUT spring-oxm module from Spring WS (packages spring-xml and spring-oxm have been integrated into Spring since Spring 3).

            I got the UnsupportedOperationException error when runngin XmlFunctionalTests :
            Code:
            java.lang.UnsupportedOperationException: XStreamMarshaller does not support unmarshalling using SAX XMLReaders
            	at org.springframework.oxm.xstream.XStreamMarshaller.unmarshalSaxReader(XStreamMarshaller.java:460)
            	at org.springframework.oxm.support.AbstractMarshaller.unmarshalSaxSource(AbstractMarshaller.java:341)
            	at org.springframework.oxm.support.AbstractMarshaller.unmarshal(AbstractMarshaller.java:131)
            	at org.springframework.batch.item.xml.StaxEventItemReader.doRead(StaxEventItemReader.java:222)
            	at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:87)
            	at org.springframework.batch.sample.iosample.AbstractIoSampleTests.getCredits(AbstractIoSampleTests.java:92)
            	at org.springframework.batch.sample.iosample.AbstractIoSampleTests.testUpdateCredit(AbstractIoSampleTests.java:53)
            Test 3
            When I use the following environment :
            . Spring Batch 2.1.0.RELEASE
            . Spring 3.1.0.RELEASE
            . and WITHOUT spring-oxm and spring-xml modules from Spring WS (packages spring-xml and spring-oxm have been integrated into Spring since Spring 3).

            I got the ClassNotFoundException error when runngin XmlFunctionalTests :
            Code:
            java.lang.ClassNotFoundException : org.springframework.xml.transform.StaxSource
            Diagnosis and possible solution
            This is due to the fact that Spring 3 renamed the package org.springframework.xml.transform from Spring WS 1.5.9 into org.springframework.util.xml.

            So you must change the code for StaxEventItemReader and StaxEventItemWriter in order for Spring Batch to work with Spring 3.

            We've made the following patch and it works with Spring 3 and Spring 2.5.6/Spring WS 1.5.9.

            Should I create a JIRA ?

            Thanks for your time

            Comment


            • #7
              A JIRA would be a good idea. Thanks for tracking that down.

              A workaround is to simply use spring-oxm from WS 1.5.9 with Spring 3.0 (that's what I have been doing - assuming that this was the only solution). Using Mavne there are some exclusions to set up, but it works fine.

              Comment


              • #8
                Hello Dave,

                Just created the JIRA
                https://jira.springsource.org/browse/BATCH-1532

                Regards,
                Cyril.

                Comment

                Working...
                X