4

I am trying to access the Opendaylight APIs from my sample project and getting javax.xml.bind.UnmarshalException, when I execute the code.

I have figured out that, this exception is caused when trying to instantiate an abstract class.

But, this is the sample code from official source and I don't have control over the APIs. I tried replacing the classes from library with the classes I generated using the XSD and result is the same. Can someone tell me what is wrong or what can be done?

Here is the sample code and output. Please note, the server is configured correctly and I am getting the response.

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.codec.binary.Base64;
import org.opendaylight.controller.sal.reader.FlowOnNode;
import org.opendaylight.controller.statistics.northbound.AllFlowStatistics;
import org.opendaylight.controller.statistics.northbound.FlowStatistics;

public class JAXBStatisticsClient {

    public static void main(String[] args) {

    System.out.println("Starting Statistics JAXB client.");

    String user = "admin";
    String password = "admin";
    String containerName = "default";
    String baseURL = "http://172.18.2.95:8080/controller/nb/v2/statistics";

    try {
        URL url = new java.net.URL(baseURL + "/" + containerName + "/flow");

        String authString = user + ":" + password;
        byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
        String authStringEnc = new String(authEncBytes);

        URLConnection connection = url.openConnection();
        connection.setRequestProperty("Authorization", "Basic " + authStringEnc);
        connection.setRequestProperty("Content-Type", "application/xml");
        connection.setRequestProperty("Accept", "application/xml");
        connection.connect();

        InputStream inputStream = connection.getInputStream();
        JAXBContext context = JAXBContext.newInstance(AllFlowStatistics.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();    
        AllFlowStatistics result = (AllFlowStatistics) unmarshaller.unmarshal(inputStream);

        System.out.println("We have these statistics:");

        for (FlowStatistics statistics : result.getFlowStatistics()) {
        System.out.println("Node ID : " + statistics.getNode().getNodeIDString());
        System.out.println("Node Type : " + statistics.getNode().getType());
        if (null != statistics.getFlowStats()) {
            for (FlowOnNode flowOnNode : statistics.getFlowStats()) {
            System.out.println("\t" + flowOnNode.getByteCount());
            System.out.println("\t" + flowOnNode.getDurationNanoseconds());
            System.out.println("\t" + flowOnNode.getDurationSeconds());
            System.out.println("\t" + flowOnNode.getPacketCount());
            System.out.println("\t" + flowOnNode.getTableId());
            System.out.println("\t" + flowOnNode.getFlow());
            }
        }
        }

    } catch (Exception e) {
        System.out.println(e.getLocalizedMessage());
        e.printStackTrace();
    }
    }
}

Output

Starting Statistics JAXB client.
Unable to create an instance of org.opendaylight.controller.sal.action.Action
javax.xml.bind.UnmarshalException: Unable to create an instance of org.opendaylight.controller.sal.action.Action
 - with linked exception:
[java.lang.InstantiationException]
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader.startElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at com.odl.JAXBStatisticsClient.main(JAXBStatisticsClient.java:42)
Caused by: java.lang.InstantiationException
    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.sun.xml.internal.bind.v2.ClassFactory.create0(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.createInstance(Unknown Source)
    ... 21 more

XML output stream

<?xml version="1.0" encoding="UTF-8"?>
<list>
   <flowStatistics>
      <node>
         <id>00:00:00:00:00:00:00:01</id>
         <type>OF</type>
      </node>
      <flowStatistic>
         <flow>
            <match>
               <matchField>
                  <type>DL_TYPE</type>
                  <value>2048</value>
               </matchField>
               <matchField>
                  <mask>255.255.255.255</mask>
                  <type>NW_DST</type>
                  <value>10.0.1.1</value>
               </matchField>
            </match>
            <actions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="output">
               <type>OUTPUT</type>
               <port>
                  <node>
                     <id>00:00:00:00:00:00:00:01</id>
                     <type>OF</type>
                  </node>
                  <id>3</id>
                  <type>OF</type>
               </port>
            </actions>
            <actions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="setDlDst">
               <type>SET_DL_DST</type>
               <address>000000000001</address>
            </actions>
            <priority>500</priority>
            <idleTimeout>0</idleTimeout>
            <hardTimeout>0</hardTimeout>
            <id>0</id>
         </flow>
         <tableId>0</tableId>
         <durationSeconds>8292</durationSeconds>
         <durationNanoseconds>952000000</durationNanoseconds>
         <packetCount>0</packetCount>
         <byteCount>0</byteCount>
      </flowStatistic>
      <flowStatistic>
         <flow>
            <match>
               <matchField>
                  <type>DL_TYPE</type>
                  <value>2048</value>
               </matchField>
               <matchField>
                  <type>IN_PORT</type>
                  <value>OF|3@OF|00:00:00:00:00:00:00:01</value>
               </matchField>
            </match>
            <actions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="controller">
               <type>CONTROLLER</type>
            </actions>
            <priority>500</priority>
            <idleTimeout>0</idleTimeout>
            <hardTimeout>0</hardTimeout>
            <id>0</id>
         </flow>
         <tableId>0</tableId>
         <durationSeconds>8274</durationSeconds>
         <durationNanoseconds>701000000</durationNanoseconds>
         <packetCount>0</packetCount>
         <byteCount>0</byteCount>
      </flowStatistic>
   </flowStatistics>
</list>
vais
  • 133
  • 1
  • 8
  • Usually abstract classes will have subclasses that are differentiated using an `xsi:type=` property in the resulting XML, that is defined by the schema. The type specified in that property is how the JAXB unmarshaller knows which subclass to instantiate, and should be annotated in the library class(es) using @XmlElement(name, type) or @XmlElementRef(name, type) annotations. Might we be able to see the output XML stream so we can determine if there is an xsi:type property that is not being interpreted properly? – Ryan J May 13 '14 at 05:49
  • Hi Ryan, thanks for the comment. Please see the output stream I've added to the question. – vais May 13 '14 at 06:44
  • 1
    I'm not sure how this works for library obtained classes, but do you have references to the `Output`, `SetDlDst`, and `Controller` classes in your code? Usually, whatever type is specified in the xsi:type= property is what will actually be instantiated. This error leads me to believe the unmarshaller does not have a mapping for any of the subclasses, hence your error. – Ryan J May 13 '14 at 17:19
  • Spot on. I have already figured that out and added explicit references to the mentioned classes. I did it by changing code JAXBContext context = JAXBContext.newInstance(AllFlowStatistics.class, Action.class, Controller.class, Output.class, SetDlDst.class); But I don't think what I've done is the right way. In fact, I had to add references to all classes in 'action' package to make it work properly in different scenarios. Any suggestions? – vais May 14 '14 at 04:41
  • Actually, I think that is the right way to do it. You need to supply all classes that could potentially be instantiated when you ask for a new context. If that's not the right way, then I'm in the same boat you are. – Ryan J May 14 '14 at 04:56
  • I get your point. What i really wish is JAXB to take care of all the subclasses, once the root element is specified. Because explicitly listing all the referenced subclasses seems a bit odd. And you can easily miss out one or two, when using libraries. – vais May 14 '14 at 05:15
  • Think about it this way... how would JAXB know which subclasses to instantiate if you didn't tell it? It seems odd, but it's necessary. Not that I don't think you get it, but take this for example: If I wiped your brain, then gave you a class called "Shape" and said give me all instances of any shape I ask for, would you inherently know that a "Dodecahedron" was a shape? Even if you did, would you know how to make one without the definition? I think you're on the right track. – Ryan J May 14 '14 at 05:20
  • Happy to be on the right track :). But, I do have a doubt. Doesn't the annotations take care of subclasses? Please excuse my ignorance. – vais May 14 '14 at 06:14
  • Not if you don't tell it which classes are annotated... – Ryan J May 14 '14 at 08:25
  • @vais why not try including the entire package in one go like this:- JAXBContext.newInstance( "com.acme.foo:com.acme.bar" ) as mentioned in the link:- http://docs.oracle.com/javaee/7/api/javax/xml/bind/JAXBContext.html – Manjunath Aug 16 '14 at 09:45

0 Answers0