Having trouble unmarshalling a WADL - java

I need to query some endpoints for their WADLs, and test all the endpoints contained in the WADL. I'm using JaxB to unmarshal the WADL into POJOs (tried Jackson too, but got another error).
Here's the beginning of the XML:
<application>
<grammars/>
<resources base="https://gatewaydsapdev1.company.com/v2">
<resource path="/contents">
<resource path="/labels">
<method name="GET">
<request>
<param name="include" style="query" type="string"/>
<param name="q" style="query" type="string"/>
<param name="offset" style="query" type="string"/>
<param name="limit" style="query" type="string"/>
<param name="flush" style="query" type="boolean"/>
</request>
<response>
<representation element="Response" mediaType="application/json;charset=utf-8"/>
</response>
</method>
</resource>
....
And here's the unmarshalling code:
JAXBContext jaxbContext = JAXBContext.newInstance(WadlApplication.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(xml);
WadlApplication application = (WadlApplication) unmarshaller.unmarshal(reader);
But I get this exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"application"). Expected elements are <{http://wadl.dev.java.net/2009/02}application>,<{http://wadl.dev.java.net/2009/02}doc>,<{http://wadl.dev.java.net/2009/02}grammars>,<{http://wadl.dev.java.net/2009/02}include>,<{http://wadl.dev.java.net/2009/02}link>,<{http://wadl.dev.java.net/2009/02}method>,<{http://wadl.dev.java.net/2009/02}option>,<{http://wadl.dev.java.net/2009/02}param>,<{http://wadl.dev.java.net/2009/02}representation>,<{http://wadl.dev.java.net/2009/02}request>,<{http://wadl.dev.java.net/2009/02}resource>,<{http://wadl.dev.java.net/2009/02}resource_type>,<{http://wadl.dev.java.net/2009/02}resources>,<{http://wadl.dev.java.net/2009/02}response>
I don't know how to give the ObjectFactory the data it says is missing. Does anyone have any suggestions? TIA!

Your XML does not have a namespace whereas your JAXB classes do have the namespace http://wadl.dev.java.net/2009/02.
Either add namespace to the XML or drop it from your JAXB classes.

Related

java XML parsing using jaxb or dom?

I have a following xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Abc version="3" xmlns="urn:Abc-v3">
<Ele1>
<SubElement name ="name" description="DO">
<Node version="C" siteURL="https://example.com" />
<Client>
<ClientId>1</ClientId>
<ClientSecret>Yes</ClientSecret>
</Client>
</SubElement>
<SubElement name ="SharePointOLDev1" description="DEV1">
<Node version="C" siteURL="https://example.com" />
<Local>
<LocalId>id</LocalId>
<Password>password</Password>
</Local>
</SubElement>
<SubElement name="AS" description="wow">
<DB connection="connection" />
</SubElement>
</Ele1>
<Ele2>
<Content ID="A" co="LD">
<Description>Simple Docs</Description>
<Serve
Lib1="TEST"
Lib2="yes"
Lib3="yes"
Lib4="no"
Lib5="no"
Lib6="name">
<Hole enabled="false" count="200" />
<Fol enabled="false" count="100" />
<Role enabled="No" validate="false" />
<FetchFilenameAttribute connection="SAP-AS" delay="3" />
</Serve>
</Content>
<Content ID="B" co="OL">
<Description>Simple Docs </Description>
<Serve
Lib1="TEST"
Lib2="yes"
Lib3="yes"
Lib4="no"
Lib5="no"
Lib6="name"">
<Hole enabled="false" count="200" />
<Fol enabled="false" count="100" />
<Role enabled="No" validate="false" />
</Serve>
</Content>
</Ele2>
<Ele3>
<CNode attr="hai" attr1="bye" />
</Ele3>
</Abc>
I need to parse this XML file and assign values to its corresponding class objects.Which is the best option to parse such an xml file.
JAXB sounds good to me but the POJOs were already written by someone and now i will have to rewrite and deploy them.ALso teh xml file has some errors while running xjc command.
DOM approach seems to be very cumbersome n error prone.
Please suggest.
PS:Kindly excuse my beginner level knowledge.
the JDK project comes with SAX(Simple API for XML) accessible by importing org.xml.sax.*.
You may take a look at this https://www.tutorialspoint.com/java_xml/java_sax_parse_document.htm for an introduction to the subject.

How to add Annotations elements in metadata generated by Apache Olingo V2.0?

I have developed Odata service for a system entity which generates a metadata but however I cant figure out how to add Annotations element to it. Sample Metadata generated is as follows :-
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:sap="http://www.sap.com/Protocols/SAPData" Version="1.0">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
m:DataServiceVersion="1.0">
<Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" Namespace="myNamespace" sap:schema-version="1">
<EntityType Name="System">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="name" Type="Edm.String" sap:label="System Name" sap:creatable="false"
sap:updatable="false" sap:sortable="false" sap:required-in-filter="true"/>
<Property Name="description" Type="Edm.String" />
<Property Name="status" Type="Edm.String" />
<Property Name="type" Type="Edm.String" />
</EntityType>
<EntityContainer Name="ODataEntityContainer" m:IsDefaultEntityContainer="true">
<EntitySet Name="Systems" EntityType="myNamespace.System" />
<FunctionImport Name="NumberOfSystems" ReturnType="Collection(myNamespace.System)"
m:HttpMethod="GET" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
I need to add following elements to above metatada
<Annotations Target="myNamespace.System"
xmlns="http://docs.oasis-open.org/odata/ns/edm">
<Annotation Term="com.sap.vocabularies.UI.v1.LineItem">
<Collection>
<Record Type="com.sap.vocabularies.UI.v1.DataField">
<PropertyValue Property="Value" Path="name" />
</Record>
<Record Type="com.sap.vocabularies.UI.v1.DataField">
<PropertyValue Property="Value" Path="description"/>
</Record>
<Record Type="com.sap.vocabularies.UI.v1.DataField">
<PropertyValue Property="Value" Path="status" />
</Record>
</Collection>
</Annotation>
</Annotations>
I came across the org.apache.olingo.commons.api.edm.provider.annotation package but cant find any suitable API. Please let me know how should I proceed.
Thanks in advance.
The annotations you would like to use have been introduced with OData V3 which is why they are not directly supported with the Olingo V2 library.
You can use the EdmProvider AnnotationElement and AnnotationAttribute classes to mimic this behaviour though. For example You can create a AnnotationElement with the name "Annotations" this element will then have the "AnnotationAttribute" Target=SomeString. Since an "AnnotationElement" can have child elements you can put your Collection element there. Namespaces are also handled with "AnnotationAttributes".
You can only attach the annotation to Edm elements which are derived from the EdmAnnotatable interface. So this is a difference to V3.
This is currently the only way to get this behaviour with Olingo V2.

Jaxb implClass specification ignored for rootElement

I'm trying to specify a implementation class for an XSD-Type.
Here's a minimal example schema:
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="rd.test"
xmlns:tns="rd.test" elementFormDefault="qualified"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<complexType name="DocumentType">
<annotation>
<appinfo>
<jaxb:class implClass="rd.DocumentEx" />
</appinfo>
</annotation>
<sequence>
<element name="element" type="tns:DocumentType" />
</sequence>
<attribute name="title" type="string" />
</complexType>
<element name="document" type="tns:DocumentType"/>
</schema>
I'm using the standard xjc-tool from the Java JDK (1.7) for now (but I've also tested with maven-jaxb2-plugin, with the same results).
For a short test I used the following XML-document:
<?xml version='1.0' standalone='yes' ?>
<document title="testDocument">
<element title="testElement" />
</document>
When I run the following test program, the results differ for the top-level document element (testDocument) and the contained child element (testElement). The root is of type "DocumentType", i.e. ignoring the specified implClass-directive, whereas the element is of type "DocumentEx", which is the expected result.
In the generated ObjectFactory the appropriate instantiation seems correct, but it seems to be not used for the rootElement:
public DocumentType createDocumentType() {
return new DocumentEx();
}
Here is the test program:
InputStream inp=new FileInputStream(new File("test.xml"));
JAXBContext jaxbContext = JAXBContext.newInstance("test.rd");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement el = (JAXBElement)unmarshaller.unmarshal(inp);
Object obj = el.getValue();
System.out.println("doc: " + obj);
// result: "doc: test.rd.DocumentType#d1c5bb0"
DocumentType doc = (DocumentType)obj;
Object obj2=doc.getElement();
System.out.println("obj2: " + obj2);
// result: "obj2: rd.DocumentEx#d1c5bb0"
I get the same result, if I specify the implClass for the element instead of for the complexType.
Why is the implClass ignored for the root-element?
Any ideas and hints are appreciated!
Extension to clarify my intention:
I don't want to reference an existing, jaxb-annotated class, but use the auto-generated DocumentType-Class as base class for extionsion with additional attributes and methods. For a later direct marshalling back to XML, I have to keep the relation to the XSD-Type. Therefore the implClass-directive actually is the appropriate (as far as I know) way to instrument the jaxb-generation of the type-classes.
And it's working perfectly for the inner elements (the 'element' with title 'testElement' inside the document-tag)!! Unfortunately the unmarshaller does NOT use the implClass-specified class for instantiating the root-element correctly. See the result-comments in the program excerpt above (doc vs. obj2).
For the behaviour you are looking for I believe you want to specify ref and not impl:
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="rd.test"
xmlns:tns="rd.test" elementFormDefault="qualified"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<complexType name="DocumentType">
<annotation>
<appinfo>
<jaxb:class ref="rd.DocumentEx" />
</appinfo>
</annotation>
<sequence>
<element name="element" type="tns:DocumentType" />
</sequence>
<attribute name="title" type="string" />
</complexType>
<element name="document" type="tns:DocumentType"/>
</schema>
This tells JAXB to use the rd.DocumentEx class for the DocumentType complex type. Now a DocumentType class is not created, and the createDocument method on the ObjectFactory looks like this:
#XmlElementDecl(namespace = "rd.test", name = "document")
public JAXBElement<DocumentEx> createDocument(DocumentEx value) {
return new JAXBElement<DocumentEx>(_Document_QNAME, DocumentEx.class, null, value);
}
From section 7.7.1 of the JAXB 2.2 specification:
• implClass if specified, is the name of the implementation class for
className and must include the complete package name. Note that this
customization only impacts the return value for className’s factory
method. This customization is ignored when new is used to create
instances of a schema-derived Value class.
• ref if specified, is the
name of the value class that is provided outside the schema compiler.
This customization causes a schema compiler to refer to this external
class, as opposed to generate a definition. It must include the
complete package name. This attribute is mutually exclusive with the
className attribute and the implClass attribute.

How to construct the WADL file to get following Java interface

I am very new to REST services .. I want to create a WADL which I will be converting to Java interface to create and expose a Rest web service .. So .. I need to create a WADL to get the following java interface :-
#Path("/getData")
public interface MainData {
#GET
#Produces("application/json")
#Path("/retrieve/")
public DataResponse retrieveDataOperation(#QueryParam("id") int id);
#POST
#Produces("application/json")
#Path("/insert/")
public DataResponse insertDataOperation(String message);
#PUT
#Produces("application/json")
#Path("/update/")
public DataResponse updateDataOperation(String message);
#DELETE
#Produces("application/json")
#Path("/delete/")
public DataResponse deleteDataOperation(#QueryParam("id") int id);
}
So far I tried to create the following WADL to get the above interface :-
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://wadl.dev.java.net/2009/02 wadl.xsd"
xmlns:ns1="http://services.test.com/schema/bs/bom/v01/GetAllTypeDesignators"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://wadl.dev.java.net/2009/02">
<grammars>
<include href="MainData.xsd" />
</grammars>
<resources base="http://localhost:8082">
<resource path="getData" id="com.test.services.schema.maindata.v1.MainData">
<resource path="/retrieve/" >
<method name="GET" id="retrieveDataOperation">
<request>
<param type="xs:int" style="query" name="id"/>
</request>
<response>
<representation mediaType="application/json" element="ns1:DataResponse"/>
</response>
</method>
</resource>
<resource path="/delete/" >
<method name="DELETE" id="deleteDataOperation">
<request>
<param type="xs:int" style="query" name="id"/>
</request>
<response>
<representation mediaType="application/json" element="ns1:DataResponse"/>
</response>
</method>
</resource>
<resource path="/insert/" >
<method name="POST" id="insertDataOperation">
<request>
<param name="message" type="xs:string" />
</request>
<response>
<representation mediaType="application/json" element="ns1:DataResponse"/>
</response>
</method>
</resource>
<resource path="/update/" >
<method name="PUT" id="updateDataOperation">
<request>
<param name="message" type="xs:string" />
</request>
<response>
<representation mediaType="application/json" element="ns1:DataResponse"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
But I am not able to get the Java interface above after converting this WADL to Java .. While converting in Apache CXF it also shows following exception :- WADLToJava Error: java.lang.NullPointerException
Please help me to to modify the WADL to get the exact java interface above .. Am I doing in right way .. Please help ..
I have just check your WADL and it looks ok, few minor mistakes but nothing which point to your error. Also, I have used command line tool wadl2java;
wadl2java -d /output/dir -interface /input/wadl/application.wadl
Here is corrected WADL;
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:ns1="http://services.test.com/schema/bs/bom/v01/GetAllTypeDesignators">
<grammars>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://services.test.com/schema/bs/bom/v01/GetAllTypeDesignators">
<xs:element name="dataResponse" type="ns1:dataResponse"/>
<xs:complexType name="dataResponse">
<xs:sequence>
<xs:element name="param1" type="xs:int"/>
<xs:element name="param2" type="xs:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</grammars>
<resources base="http://localhost:8082">
<resource path="getData" id="com.test.services.schema.maindata.v1.MainData">
<resource path="/retrieve/" >
<method name="GET" id="retrieveDataOperation">
<request>
<param type="xs:int" style="query" name="id"/>
</request>
<response>
<representation mediaType="application/json" element="ns1:dataResponse"/>
</response>
</method>
</resource>
<resource path="/delete/" >
<method name="DELETE" id="deleteDataOperation">
<request>
<param type="xs:int" style="query" name="id"/>
</request>
<response>
<representation mediaType="application/json" element="ns1:dataResponse"/>
</response>
</method>
</resource>
<resource path="/insert/" >
<method name="POST" id="insertDataOperation">
<request>
<representation mediaType="*/*">
<param name="message" style="plain" type="xs:string" />
</representation>
</request>
<response>
<representation mediaType="application/json" element="ns1:dataResponse"/>
</response>
</method>
</resource>
<resource path="/update/" >
<method name="PUT" id="updateDataOperation">
<request>
<representation mediaType="*/*">
<param name="message" style="plain" type="xs:string" />
</representation>
</request>
<response>
<representation mediaType="application/json" element="ns1:dataResponse"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>
You should post your MainData.xsd, I'll bet that inside your XSD relies your error.
UPDATE:
It appears that param name must be lowerCase of the param type if it used in "representation". I have just check the source code of the wadl2java (cxf-tools-wadlto-jaxrs-3.0.1-sources.jar) and concluded that modification of generator is required. Problematic line is in class org.apache.cxf.tools.wadlto.jaxrs.SourceGenerator:1044 which looks like elementParamName = elementParamType.toLowerCase(); You should report that on Apache CXF jira or modify code by yourself.
Alternative is to set your message param as #QueryParam, you can do that by replacing;
<representation mediaType="*/*">
<param name="message" style="plain" type="xs:string" />
</representation>
with this;
<param name="message" style="query" type="xs:string" />
but in that case your interface method will look like;
#POST
#Produces("application/json")
#Path("/insert/")
DataResponse insertDataOperation(#QueryParam("message") String message);
Hope it helps.

Castor unmarshalling auto named primitive types

First of all, please excuse my poor English
Can you please advice how I can unmarshal following XML structure:
<elements>
<element>
<long>1</long>
</element>
<element>
<string>Test</string>
</element>
<element>
<long>5</long>
</element>
</elements>
where long, string - basic JAVA types.
Here is how each "element" is described for marshaling:
<class
name="com.test.MessageElement"
verify-constructable="false">
<field name="element">
<bind-xml auto-naming="deriveByClass" />
</field>
</class>
Thank you in advance

Categories