Hi, I've implemented JSON mapping support for data services, which is basically, rather than defining the XML elements in the result, now we can give a JSON message template to provide how the JSON representation would be in the result.
The following is a sample of a data services result element for JSON
mapping:-
<query id="customersInBostonSQL" useConfig="default">
<sql>select * from Customers where city = 'Boston' and country =
'USA'</sql>
<result outputType="json">
{
"customers":{
"customer":[
{
"phone":"$phone",
"city":"$city",
"contact":{
"customer-name":"$customerName",
"contact-last-name":"$contactLastName",
"contact-first-name":"$contactFirstName"
}
}
]
}
}
</result>
</query>
So here, the "result" element's "outputType" value is set to "json" (we had
"xml" and "rdf", defaulting to "xml"). So here, to refer to result set's
columns / query-params, we have used the convention of prefixes the name of
the parameter with "$", which basically signals we are looking up a value.
Also, since this is a template based approach, for other special properties
like output fields data types, required roles (used for content filtering)
needs to be specified in a special way encoded in the value of a field.
This is done in the following way,
{ "age" : "$age(type:integer;requiredRoles:r1,r2) } ..
So the first part is the looked up variable (column), and the section
covered by "(" and ")" specifies the extended attributed.
Also, another feature to support here are nested queries, that means, from
the JSON mapping, we should be able to specify a query to be executed and
its result be replaced at the place it was invoked. For this, I've at the
moment implemented in the following way:
{"phone":"$phone",
"@employeesInOfficeSQL":"$officeCode->officeCode,$param2->param2" } ..
So basically here, calling a query is symbolized by prefixing the field
name with an "@", where the name of the target query will follow, and the
value of the field will contain the parameter mappings, that is out column
values map to target query's params, which is connected with a "->"
operator. I personally prefer a short symbol like "@" to denote the nested
query option, rather than having a keyword like "operation", where this is
more compact.
So this mapping works fully when used with the GSON based streaming JSON
implementation [1], that is, if we say, the records are in an JSON array,
it will always return as an array, even if the result just gives out a
single object. This is done by the JSON message formatter looking at the
XML schema created. But, this does not work with nested queries, where the
default JSON message formatter works properly. I've verified the XML schema
generated do conform to the message returned by the service calls, so this
seems like a bug in the new JSON message formatter. I'm attaching here the
data service I'm using, and also the WSDL of it. Below contains some sample
requests you can do against the data service.
(run all with HTTP header "Accept: application/json", and HTTP GET)
* "http://10.100.1.45:9763/services/JSONSample/boston_customers"
* "http://10.100.1.45:9763/services/JSONSample/employee/1002"
* "http://10.100.1.45:9763/services/JSONSample/offices" (nested query
request)
A DSS build with the JSON mapping features can be found here [2], download
it and configure the streaming JSON message formatter as explained at [1].
@Shameera, can you please try this out and figure out what the issue might
be with the complex result outputs, and if it's a bug in the JSON message
formatter, appreciate if you can provide a fix for it.
[1]
https://builds.apache.org/job/Axis2/javadoc/docs/json_gson_user_guide.html
[2]
https://svn.wso2.org/repos/wso2/people/anjana/tmp/wso2dss-3.2.0-20140227.zip
Cheers,
Anjana.
--
*Anjana Fernando*
Technical Lead
WSO2 Inc. | http://wso2.com
lean . enterprise . middleware
JSONSample.dbs
Description: Binary data
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://ws.wso2.org/dataservice/samples/nested_query_sample/employeesByNumberSQL" xmlns:ns1="http://ws.wso2.org/dataservice/samples/nested_query_sample/employeesInOfficeSQL" xmlns:ns4="http://ws.wso2.org/dataservice/samples/nested_query_sample/customersInBostonSQL" xmlns:ns3="http://ws.wso2.org/dataservice" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns="http://ws.wso2.org/dataservice/samples/nested_query_sample" xmlns:ns0="http://ws.wso2.org/dataservice/samples/nested_query_sample/listOfficesSQL" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://ws.wso2.org/dataservice/samples/nested_query_sample"> <wsdl:documentation></wsdl:documentation> <wsdl:types> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://ws.wso2.org/dataservice/samples/nested_query_sample/listOfficesSQL"> <xs:import namespace="http://ws.wso2.org/dataservice/samples/nested_query_sample/employeesInOfficeSQL"></xs:import> <xs:element name="_getoffices"> <xs:complexType> <xs:sequence></xs:sequence> </xs:complexType> </xs:element> <xs:element name="Offices" type="ns0:Offices"></xs:element> <xs:complexType name="Offices"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="Office" type="ns0:Office"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="Office"> <xs:sequence> <xs:element name="phone" nillable="true" type="xs:string"></xs:element> <xs:element name="officeCode" nillable="true" type="xs:integer"></xs:element> <xs:element ref="ns1:Employees"></xs:element> <xs:element name="country" nillable="true" type="xs:string"></xs:element> <xs:element name="city" nillable="true" type="xs:string"></xs:element> </xs:sequence> </xs:complexType> </xs:schema> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://ws.wso2.org/dataservice/samples/nested_query_sample/employeesInOfficeSQL"> <xs:element name="Employees" type="ns1:Employees"></xs:element> <xs:complexType name="Employees"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="Employee" type="ns1:Employee"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="Employee"> <xs:sequence> <xs:element name="email" nillable="true" type="xs:string"></xs:element> <xs:element name="firstName" nillable="true" type="xs:string"></xs:element> <xs:element name="employeeNumber" nillable="true" type="xs:integer"></xs:element> </xs:sequence> </xs:complexType> </xs:schema> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://ws.wso2.org/dataservice/samples/nested_query_sample/employeesByNumberSQL"> <xs:element name="_getemployee_employeenumber"> <xs:complexType> <xs:sequence> <xs:element name="employeeNumber" nillable="true" type="xs:int"></xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="employees" type="ns2:employees"></xs:element> <xs:complexType name="employees"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="employee" type="ns2:employee"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="employee"> <xs:sequence> <xs:element name="lastName" nillable="true" type="xs:string"></xs:element> <xs:element name="salary" nillable="true" type="xs:double"></xs:element> <xs:element name="firstName" nillable="true" type="xs:string"></xs:element> </xs:sequence> </xs:complexType> </xs:schema> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://ws.wso2.org/dataservice"> <xs:element name="DataServiceFault" type="xs:string"></xs:element> <xs:element name="REQUEST_STATUS" type="xs:string"></xs:element> <xs:element name="DATA_SERVICE_RESPONSE"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0"></xs:any> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://ws.wso2.org/dataservice/samples/nested_query_sample/customersInBostonSQL"> <xs:element name="_getboston_customers"> <xs:complexType> <xs:sequence></xs:sequence> </xs:complexType> </xs:element> <xs:element name="customers" type="ns4:customers"></xs:element> <xs:complexType name="customers"> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="customer" type="ns4:customer"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="customer"> <xs:sequence> <xs:element name="phone" nillable="true" type="xs:string"></xs:element> <xs:element ref="ns4:contact"></xs:element> <xs:element name="city" nillable="true" type="xs:string"></xs:element> </xs:sequence> </xs:complexType> <xs:element name="contact" type="ns4:contact"></xs:element> <xs:complexType name="contact"> <xs:sequence> <xs:element name="contact-last-name" nillable="true" type="xs:string"></xs:element> <xs:element name="customer-name" nillable="true" type="xs:string"></xs:element> <xs:element name="contact-first-name" nillable="true" type="xs:string"></xs:element> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="_getboston_customersRequest"> <wsdl:part name="parameters" element="ns4:_getboston_customers"></wsdl:part> </wsdl:message> <wsdl:message name="_getboston_customersResponse"> <wsdl:part name="parameters" element="ns4:customers"></wsdl:part> </wsdl:message> <wsdl:message name="DataServiceFault"> <wsdl:part name="parameters" element="ns3:DataServiceFault"></wsdl:part> </wsdl:message> <wsdl:message name="_getofficesRequest"> <wsdl:part name="parameters" element="ns0:_getoffices"></wsdl:part> </wsdl:message> <wsdl:message name="_getofficesResponse"> <wsdl:part name="parameters" element="ns0:Offices"></wsdl:part> </wsdl:message> <wsdl:message name="_getemployee_employeenumberRequest"> <wsdl:part name="parameters" element="ns2:_getemployee_employeenumber"></wsdl:part> </wsdl:message> <wsdl:message name="_getemployee_employeenumberResponse"> <wsdl:part name="parameters" element="ns2:employees"></wsdl:part> </wsdl:message> <wsdl:portType name="JSONSamplePortType"> <wsdl:operation name="_getboston_customers"> <wsdl:documentation></wsdl:documentation> <wsdl:input message="tns:_getboston_customersRequest" wsaw:Action="urn:_getboston_customers"></wsdl:input> <wsdl:output message="tns:_getboston_customersResponse" wsaw:Action="urn:_getboston_customersResponse"></wsdl:output> <wsdl:fault message="tns:DataServiceFault" name="DataServiceFault" wsaw:Action="urn:_getboston_customersDataServiceFault"></wsdl:fault> </wsdl:operation> <wsdl:operation name="_getoffices"> <wsdl:documentation></wsdl:documentation> <wsdl:input message="tns:_getofficesRequest" wsaw:Action="urn:_getoffices"></wsdl:input> <wsdl:output message="tns:_getofficesResponse" wsaw:Action="urn:_getofficesResponse"></wsdl:output> <wsdl:fault message="tns:DataServiceFault" name="DataServiceFault" wsaw:Action="urn:_getofficesDataServiceFault"></wsdl:fault> </wsdl:operation> <wsdl:operation name="_getemployee_employeenumber"> <wsdl:documentation></wsdl:documentation> <wsdl:input message="tns:_getemployee_employeenumberRequest" wsaw:Action="urn:_getemployee_employeenumber"></wsdl:input> <wsdl:output message="tns:_getemployee_employeenumberResponse" wsaw:Action="urn:_getemployee_employeenumberResponse"></wsdl:output> <wsdl:fault message="tns:DataServiceFault" name="DataServiceFault" wsaw:Action="urn:_getemployee_employeenumberDataServiceFault"></wsdl:fault> </wsdl:operation> </wsdl:portType> <wsdl:binding name="JSONSampleSOAP11Binding" type="tns:JSONSamplePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding> <wsdl:operation name="_getboston_customers"> <soap:operation soapAction="urn:_getboston_customers" style="document"></soap:operation> <wsdl:input> <soap:body use="literal"></soap:body> </wsdl:input> <wsdl:output> <soap:body use="literal"></soap:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap:fault use="literal" name="DataServiceFault"></soap:fault> </wsdl:fault> </wsdl:operation> <wsdl:operation name="_getoffices"> <soap:operation soapAction="urn:_getoffices" style="document"></soap:operation> <wsdl:input> <soap:body use="literal"></soap:body> </wsdl:input> <wsdl:output> <soap:body use="literal"></soap:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap:fault use="literal" name="DataServiceFault"></soap:fault> </wsdl:fault> </wsdl:operation> <wsdl:operation name="_getemployee_employeenumber"> <soap:operation soapAction="urn:_getemployee_employeenumber" style="document"></soap:operation> <wsdl:input> <soap:body use="literal"></soap:body> </wsdl:input> <wsdl:output> <soap:body use="literal"></soap:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap:fault use="literal" name="DataServiceFault"></soap:fault> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:binding name="JSONSampleSOAP12Binding" type="tns:JSONSamplePortType"> <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap12:binding> <wsdl:operation name="_getboston_customers"> <soap12:operation soapAction="urn:_getboston_customers" style="document"></soap12:operation> <wsdl:input> <soap12:body use="literal"></soap12:body> </wsdl:input> <wsdl:output> <soap12:body use="literal"></soap12:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap12:fault use="literal" name="DataServiceFault"></soap12:fault> </wsdl:fault> </wsdl:operation> <wsdl:operation name="_getoffices"> <soap12:operation soapAction="urn:_getoffices" style="document"></soap12:operation> <wsdl:input> <soap12:body use="literal"></soap12:body> </wsdl:input> <wsdl:output> <soap12:body use="literal"></soap12:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap12:fault use="literal" name="DataServiceFault"></soap12:fault> </wsdl:fault> </wsdl:operation> <wsdl:operation name="_getemployee_employeenumber"> <soap12:operation soapAction="urn:_getemployee_employeenumber" style="document"></soap12:operation> <wsdl:input> <soap12:body use="literal"></soap12:body> </wsdl:input> <wsdl:output> <soap12:body use="literal"></soap12:body> </wsdl:output> <wsdl:fault name="DataServiceFault"> <soap12:fault use="literal" name="DataServiceFault"></soap12:fault> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:binding name="JSONSampleHttpBinding" type="tns:JSONSamplePortType"> <http:binding verb="POST"></http:binding> <wsdl:operation name="_getboston_customers"> <http:operation location="boston_customers"></http:operation> <wsdl:input> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:input> <wsdl:output> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:output> </wsdl:operation> <wsdl:operation name="_getoffices"> <http:operation location="offices"></http:operation> <wsdl:input> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:input> <wsdl:output> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:output> </wsdl:operation> <wsdl:operation name="_getemployee_employeenumber"> <http:operation location="employee/(employeeNumber)"></http:operation> <wsdl:input> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:input> <wsdl:output> <mime:content type="text/xml" part="parameters"></mime:content> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="JSONSample"> <wsdl:port name="SOAP11Endpoint" binding="tns:JSONSampleSOAP11Binding"> <soap:address location="http://10.100.1.45:9763/services/JSONSample.SOAP11Endpoint/"></soap:address> </wsdl:port> <wsdl:port name="SecureSOAP11Endpoint" binding="tns:JSONSampleSOAP11Binding"> <soap:address location="https://10.100.1.45:9443/services/JSONSample.SecureSOAP11Endpoint/"></soap:address> </wsdl:port> <wsdl:port name="SecureSOAP12Endpoint" binding="tns:JSONSampleSOAP12Binding"> <soap12:address location="https://10.100.1.45:9443/services/JSONSample.SecureSOAP12Endpoint/"></soap12:address> </wsdl:port> <wsdl:port name="SOAP12Endpoint" binding="tns:JSONSampleSOAP12Binding"> <soap12:address location="http://10.100.1.45:9763/services/JSONSample.SOAP12Endpoint/"></soap12:address> </wsdl:port> <wsdl:port name="HTTPEndpoint" binding="tns:JSONSampleHttpBinding"> <http:address location="http://10.100.1.45:9763/services/JSONSample.HTTPEndpoint/"></http:address> </wsdl:port> <wsdl:port name="SecureHTTPEndpoint" binding="tns:JSONSampleHttpBinding"> <http:address location="https://10.100.1.45:9443/services/JSONSample.SecureHTTPEndpoint/"></http:address> </wsdl:port> </wsdl:service> </wsdl:definitions>
_______________________________________________ Architecture mailing list [email protected] https://mail.wso2.org/cgi-bin/mailman/listinfo/architecture
