<?xml version="1.0"?>
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements. See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership. The ASF licenses this file
  ~ to you under the Apache License, Version 2.0 (the
  ~ "License"); you may not use this file except in compliance
  ~ with the License. You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied. See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
  -->
<document xmlns="http://maven.apache.org/XDOC/2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
   <properties>
       <title>New JSON support in Apache Axis2</title>
   </properties>

    <body>
        <h1>New JSON support in Apache Axis2</h1>
	<p>Update: Moshi support is now included as an alternative to GSON,
           though both are supported and will continue to be. Both libs are very
	   similar in features though Moshi is widely considered to have better
	   performance. GSON development has largely ceased. Switching between
	   Moshi and GSON is a matter of editing the axis2.xml file. 
	</p>
	<p>
	   For users of JSON and Spring Boot, the Native approach discussed below can be seen as a complete sample application in 
	   the <a href="json-springboot-userguide.html">JSON and Spring Boot 3 User's Guide.</a> 
	</p>
        <p>This documentation explains how the existing JSON support in Apache Axis2 have been improved with two new
            methods named, Native approach and XML stream API based approach. Here it initially explains about the
            drawbacks of the old JSON support, how to overcome those drawbacks with the new approaches and, how to use
            those approaches to send pure JSON objects without converting it to any XML representations. XML Stream API
            based approach addresses the namespace problem with pure JSON support, and provides a good solution for
            that.</p>

        <section name="Introduction">

            <p>Apache Axis2 is an efficient third generation SOAP processing web services engine. JSON (JavaScript
                Object Notation) is a lightweight data-interchange format and, an alternative for XML which is easily
                human readable and writable as well as it can be parsed and generated easily for machines.</p>

            <p>The existing JSON implementation in Apache Axis2/Java supports badgerfish format of the JSON object,
                which is an XML representation of JSON object. With this approach, it first completely converts the
                badgerfish JSON string to the relevant XML format in the server side and, treats it as a normal SOAP
                message. The current JSON implementation also supports Mapped JSON, which is another XML representation
                of the JSON object, if we set xmlToJsonNamespaceMap parameter in the services.xml file of the service.
                The main problem with Mapped JSON format is, at the client side it is not aware of the namespaces which
                is used in server side to validate the request. Therefore with current implementation, it is required
                to do modifications to the existing services to use this mapped format support. The current JSON
                implementations of Axis2 are slower than the existing SOAP support too. Therefore the existing JSON
                support doesn't expose its advantages at all.</p>

            <p>However this JSON support can be improved to support pure JSON objects without using any format to
                convert it into a XML, as JSON is a light weighted alternative to XML. Thre are two new approaches
                have been used with google-gson library, a rich library to convert a JSON string to a Java object
                and vice-versa, in order to improve the existing JSON support in Apache Axis2/java.</p>

            <p>Gson[1] is a Java library that can be used to convert Java Objects into their JSON representation.
                It can be also used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary
                Java objects including pre-existing objects for which you do not have the source code.</p>

            <p>There are a few open source projects, capable of converting Java objects into JSON. However, most of
                them require to place Java annotations in all classes; something that cannot be done if we do not have
                access to the source code. Most of them also do not fully support the use of Java Generics. Gson has
                considered both of these facts as very important design goals and, the following are some of the
                advantages of using Gson to convert JSON into Java objects and vice-versa.</p>

            <ul>
                <li>It provides simple toJSON() and fromJSON() methods to convert Java objects into JSON objects and
                    vice-versa.</li>
                <li>It allows pre-existing unmodifiable objects to be converted into/from JSON objects.</li>
                <li>It has the extensive support of Java Generics.</li>
                <li>It allows custom representations for objects.</li>
                <li>It supports arbitrarily complex objects (with deep inheritance hierarchies and extensive use of
                    generic types).</li>
            </ul>

            <p>As mentioned above, these two new approaches have been introduced to overcome the above explained
                problems in the existing JSON implementation (Badgerfish and Mapped) of Axis2. The first one, the
                Native approach, has been implemented with completely pure JSON support throughout the axis2 message
                processing process while with the second approach which is XML stream API based approach, an
                XMLStreamReader/XMLStreamWriter implementation using google-gson with the help of XMLSchema is being
                implemented. The detailed description on the two approaches is given out in the next sections of the
                documentation.</p>
        </section>

        <section name="Native Approach" id="native_approach" >

	    <p>The Native approach is for JSON use cases without a WSDL nor any XML dependency, and you just want some simple Java Objects that map to and from GSON or Moshi.</p>

            <p>With this approach you can expose your POJO service to accept pure JSON request other than converting to
                any representation or format. You just need to send a valid JSON string request to the service url and,
                in the url you should have addressed the operation as well as the service. Because in this scenario Axis2
                uses URI based operation dispatcher to dispatch the correct operation. In the docs
                <a href="json_gson_user_guide.html#native_approach">here</a> you can
                find the guide for setting up this native approach, while <a href="json-springboot-userguide.html">here</a> you can find a complete Native Approach example for the client and server with a Spring Boot 3 sample application. </p>

            <p>The Native approach is being implemented to use pure JSON throughout the axis2 message processing
                process. In Axis2 as the content-type header is used to specify the type of data in the message body,
                and depending on the content type, the wire format varies. Therefore, we need to have a mechanism to
                format the message depending on content type. We know that any kind of message is represented in Axis2
                using AXIOM, and when we serialize the message, it needs to be formatted based on content type.
                MessageFormatters exist to do that job for us. We can specify MessageFormatters along with the content
                type in axis2.xml. On the other hand, a message coming into Axis2 may or may not be XML, but for it to
                go through Axis2, an AXIOM element needs to be created. As a result, MessageBuilders are employed to
                construct the message depending on the content type.</p>

            <p>After building the message it gets pass through AXIS2 execution chain to execute the message. If the
                message has gone through the execution chain without having any problem, then the engine will hand over
                the message to the message receiver in order to do the business logic invocation. After this, it is up
                to the message receiver to invoke the service and send the response. So according to the Axis2
                architecture to accomplish this approach it is required to implement three main components, a
                MessageBuilder, a MessageReceiver and a MessageFormatter, where in this Native implementation those are
                JSONBuilder, JSONRPCMessageReceiver and JSONFomatter, to handle the pure JSON request and invoke the
                service and return a completely pure JSON string as a response. In the builder, it creates and returns
                a dummy SOAP envelop to process over execution chain, while storing input json stream and a boolean
                flag IS_JSON_STREAM as a property of input MessageContext. The next one is JSONRPCMessageReceiver which
                is an extended subclass of RPCMessageReceiver. In here it checks IS_JSON_STREAM property value, if it is
                'true' then it processes InputStream stored in input MessageContext, using JsonReader in google-gson API.
                Then it invokes request service operation by Gson in google-gson API which uses Java reflection to invoke
                the service. To write the response to wire, it stores the returned object and return java bean type, as
                properties of output MessageContext. If IS_JSON_STREAM is 'false' or null then it is handed over to its
                super class RPCMessageReceiver, in order to handle the request. This means, using JSONRPCMessageReceiver
                as the message receiver of your service you can send pure JSON messages as well as SOAP requests too.
                There is a JSONRPCInOnly-MessageReceiver which extends RPCInOnlyMessageReceiver class, to handle In-Only
                JSON requests too. In JSONformatter it gets return object and the java bean type, and writes response as
                a pure JSON string to the wire using JsonWriter in google-gson API. The native approach doesn’t support
                namespaces. If you need namespace support with JSON then go through XML Stream API based approach.</p>


        </section>

        <section name="XML Stream API Base Approach" id="xml_stream_api_base_approach" >


	    <p>XML Stream API Base Approach is for use cases with a WSDL, and in addition to SOAP you also want to support JSON. This support is currently limited to XML Elements and not XML Attributes - though if you are interested in that support please see AXIS2-6081. </p>
            <p> As you can see the native approach can only be used with POJO services but if you need to expose your
                services which is generated by using ADB or xmlbeans databinding then you need to use this XML Stream
                API based approach. With this approach you can send pure JSON requests to the relevant services.
                Similar to the native approach you need to add operation name after the service name to use uri based
                operation dispatch to dispatch the request operation.
                <a href="json_gson_user_guide.html#xml_stream_api_base_approach">Here</a> you can see the user guide
                for this XML Stream API based approach.</p>

            <p>As mentioned in Native approach, Apache Axis2 uses AXIOM to process XML. If it can be implement a way to
                represent JSON stream as an AXIOM object which provides relevant XML infoset while processing JSON
                stream on fly, that would be make JSON, in line with Axis2 architecture and will support the services
                which have written on top of xmlstream API too.</p>

            <p>There are a few libraries like jettison , Json-lib etc. which already provide this
                XMLStreaReader/XMLStreamWriter interfaces for JSON. There is no issue in converting JSON to XML, as we
                can use jettison for that, but when it comes to XML to JSON there is a problem. How could we identify
                the XML element which represent JSON array type? Yes we can identify it if there is two or more
                consecutive XML elements as jettison does, but what happen if the expected JSON array type has only one
                value? Then there is only one XML element. If we use Json-lib then xml element should have an attribute
                name called "class" value to identify the type of JSON. As you can see this is not a standard way and
                we cannot use this with Axis2 as well. Hence we can't use above libraries to convert XML to JSON
                accurately without distort expected JSON string even it has one value JSON array type.</p>

            <p>Therefore with this new improvement Axis2 have it's own way to handle incoming JSON requests and
                outgoing JSON responses. It uses GsonXMLStreamReader and GsonXMLStreamWriter which are implementations
                of XMLStreamReader/XMLStreamWriter, to handle this requests and responses. To identify expected request
                OMElement structure and namespace uri, it uses XmlSchema of the request and response operations. With
                the XmlSchema it can provide accurate XML infoset of the JSON message. To get the relevant XMLSchema
                for the operation, it uses element qname of the message. At the MessageBuilder level Axis2 doesn't know
                the element qname hence it can't get the XmlSchema of the operation. To solve this issue Axis2 uses a
                new handler call JSONMessageHandler, which executes after the RequestURIOperationDispatcher handler or optionally the JSONBasedDefaultDispatcher that can be used in the native approach though it is not mandatory (See the JSON based Spring Boot User Guide). 
                In the MessageBuilder it creates GsonXMLStreamReader parsing JsonReader instance which is created using
                inputStream and stores it in input MessageContext as a message property and returns a default SOAP
                envelop. Inside the JSONMessageHandler it checks for this GsonXMLStreamReader property, if it is not
                null and messageReceiver of the operation is not an instance of JSONRPCMessageReceiver, it gets the
                element qname and relevant XMLSchema list from the input MessageContext and pass it to
                GsonXMLStreamReader. After that it creates StAXOMBuilder passing this GsonXMLStreamReader as the
                XMLStreamReader and get the document element. Finally set this document element as child of default
                SOAP body. If Axis2 going to process XMLSchema for every request this would be a performance issue.
                To solve this, Axis2 uses an intermediate representation(XmlNode) of operation XmlSchema list and store
                it inside the ConfigurationContext with element qname as a property to use it for a next request
                which will come to the same operation. Hence it only processes XmlSchema only once for each operation.</p>

            <p>Same thing happens in the JsonFormatter, as it uses GsonXMLStreamWriter to write response to wire and
                uses intermediate representation to identify the structure of outgoing OMElement. As we know the
                structure here we can clearly identify expected JSON response. Even expected JSON string have a JSON
                Array type which has only one value. </p>

            <p>In addition, XML Stream API based approach supports namespace uri where it get namespaces from the
                operation XMLSchema and provides it when it is asked. </p>



        </section>


    </body>
</document>
