Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Simplifying XmlHttpRequest with JSON-RPC

In my day job, we decided to use a little XMLHttpRequest lovin' to populate one drop-down from another. This is my review of JSON-RPC, an open source JavaScript library and servlet for simplifying XMLHttpRequest. I considered integrate Direct Web Remoting (DWR) as well, but its java.net site was down the day I needed it. I started out with JSON-RPC 0.7, which caused some conflicts with Commons Validator client-side validation. This was fixed in the 0.8 release. JSON-RPC takes a little more setup than I care for, but it's pretty easy nonetheless:

  1. Download the 0.8 release from http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz.
  2. Add the JAR to your project and the webapps/jsonrpc/jsonrpc.js to your projects' "scripts" folder. Include this file in your SiteMesh decorator or Tiles layout. If you're not using SiteMesh or Tiles, it's high time you started.
  3. JSON-RPC currently requires that you register each class you want call methods on. In our project, I registered a Spring bean (LookupHelper) that's a singleton with references to Maps in the ServletContext. Then we used JavaScript functions to call JSON-PRC and look up units for a plant, and vice versa. I'm not going to put the LookupHelper class here - you'll have to trust its methods return a single String or a comma-separated list of Strings. To register this bean with JSON-RPC, I created an HttpSessionListener and configured it in web.xml.

    /**
     * UserListener class used to add/remove session attributes when
     * a user first logs in.  Mainly for JavaScript Remote Scripting stuff.
     *
     @author Matt Raible
     */
    public class UserListener implements HttpSessionListener, HttpSessionAttributeListener 
        private final Log log = LogFactory.getLog(UserListener.class);
        public final static String BRIDGE_KEY = "JSONRPCBridge";

        /**
         * Initializes LookupHelper singleton with values needed for lookup
         *
         @param event the HttpSessionEvent to grab session information from
         */
        public void sessionCreated(HttpSessionEvent event) {
            // Find the JSONRPCBridge for this session or create one
            // if it doesn't exist. Note the bridge must be named BRIDGE_KEY
            // in the HttpSession for the JSONRPCServlet to find it.
            HttpSession session = event.getSession();
            JSONRPCBridge jsonBridge = new JSONRPCBridge();
            jsonBridge.setDebug(true);
            session.setAttribute(BRIDGE_KEY, jsonBridge);
        }

        /**
         * Destroys LookupHelper
         *
         @param event the HttpSessionEvent to grab session information from
         */
        public void sessionDestroyed(HttpSessionEvent event) {
            if (event.getSession() != null) {
                event.getSession().removeAttribute(BRIDGE_KEY);
            }
        }

        public void attributeAdded(HttpSessionBindingEvent event) {
            if (event.getName().equals(BRIDGE_KEY)) {
                HttpSession session = event.getSession();
                // register LookupHelper so we can call methods on it
                ApplicationContext ctx =
                        WebApplicationContextUtils
                        .getWebApplicationContext(session.getServletContext());

                // check for null so we don't have to initialize Spring in tests
                if (ctx != null) {
                    log.debug("Registering lookupHelper for XmlHttpRequest...");
                    JSONRPCBridge jsonBridge =
                        (JSONRPCBridgesession.getAttribute(BRIDGE_KEY);
                    jsonBridge.registerObject("lookupHelper",
                                              ctx.getBean("lookupHelper"));
                }
            }
        }

        public void attributeRemoved(HttpSessionBindingEvent event) {
            // don't care
        }

        public void attributeReplaced(HttpSessionBindingEvent event) {
            // same as attribute added
            attributeAdded(event);
        }
    }

  4. After this setup was complete, I was able to add the following JavaScript to the bottom of my JSP. These are functions that our drop-downs call to populate each other, and keep their options in synch.

    <script type="text/javascript">
    var jsonurl = "${ctx}/jsonrpc";
    var jsonrpc = null;
    var unitDropDown = document.getElementById("equipmentName");

    function filterUnits(plantDropDown) {
        var plantName = plantDropDown.options[plantDropDown.selectedIndex].value;

        if (plantName == "") {
            reloadUnits("");
            return;
        }

        try {
            jsonrpc = new JSONRpcClient(jsonurl);
        catch(e) {
            alert(e);
        }

        // Call a Java method on the server
        var units = jsonrpc.lookupHelper.getUnitsForPlant(plantName);
        setUnits(units);
    }

    function reloadUnits(value) {
        if (value == "") {
            try {
                jsonrpc = new JSONRpcClient(jsonurl);
            catch(e) {
                alert(e);
            }

            // Call a Java method on the server
            var units = jsonrpc.lookupHelper.getAllUnits();
            setUnits(units);
        }
    }

    function setUnits(units) {
        var unitArray = units.split(",");

        unitDropDown.options.length = 1;  // keep "All" option
        for (i=0; i < unitArray.length; i++) {
            unitDropDown.options[unitDropDown.options.length=
                new Option(unitArray[i], unitArray[i]);
        }
    }
    </script>

The hardest part of using JSON-RPC is setting it up. We only experienced minor issues with Commons Validator, but since the JSON-RPC 0.8 release - everything has worked great, on all browsers we need to support. The only thing I don't like about this library is that you have to register objects for each user's session. I briefly looked at DWR and it looks a little cleaner - especially b/c of its Spring integration. The next time we need XMLHttpRequest, we'll probably use DWR just to compare the two.

Posted in Java at Mar 03 2005, 08:44:40 AM MST 8 Comments
Comments:

There's another one:
http://sourceforge.net/projects/japano
This XML-RPC is a very nice thing, especially when one has components that already know how to talk to the server: http://www.domapi.com/
However, the best way would be if the Web Frameworks by themselfs would have real support for XML-RPC (e.g. Tapestry, Spring, Struts with a plug-in, etc.)
This way, the programmer wouldn't even care about this, and only choose the right component or tag - just dreaming :).

Posted by Ahmed Mohombe on March 03, 2005 at 04:30 PM MST #

Hi Matt! XML-RPC sounds great! Since I'm a subscriber to Spring Live, I'm curious, whether you want to write about this technology in it. I've ran through the DRW site - since you've mentioned possible Spring integration with it. Is it possible to drop custom property binders away and use DRW instead (for conversion of e.g.: strings, numbers and collections)? It'd be cool to see some example in your book, sometime.

Posted by Thomas Sandor on March 03, 2005 at 05:14 PM MST #

Great! I knew it exists but lost the link. I tried the examples provided on the DWR website but the feature that I really could use (adding and removing table rows) does not work with IE6. There are more and more applications that don't work with IE...

Posted by Lars Fischer on March 03, 2005 at 09:24 PM MST #

A very cool implementation of this standard is on Google's "Suggest" site, as you type, a drop-down of suggestions are made for you (pulled r/t from the google server via XMLHttpRequest)

http://www.google.com/webhp?complete=1&hl=en

Further info on the tech implementation is available on the "Learn More" link on the site:

http://labs.google.com//suggestfaq.html

Love it myself.

Posted by David Thompson on March 03, 2005 at 09:42 PM MST #

(Sorry for the double post)

Another good blog article concerning XMLHttpRequest from "The Man in Blue":

<a href"http://www.themaninblue.com/writing/perspective/2005/03/02/">http://www.themaninblue.com/writing/perspective/2005/03/02/

Posted by David Thompson on March 03, 2005 at 09:50 PM MST #

I discovered json as a potential protocol alternative while writing a pure javascript interface to Macromedia's Flash Remoting components. It was limited to support for Javascript primitives only. Objects such as Date() could not be serialized. This was a dealbreaker for me.

Posted by Jim Cook on March 04, 2005 at 02:05 PM MST #

> The only thing I don't like about this library is that you have to register

> objects for each user's session.

Matt. It looks like this library can do what you want.

From http://oss.metaparadigm.com/jsonrpc/manual.html :

Global bridge

There is a global bridge singleton object that allows exporting objects to all HTTP clients. This can be used for registering factory classes although care must be taken with authentication and security issues as these objects will be accessible to all clients. It can be fetched with JSONRPCBridge.getGlobalBridge().

To export all instance methods of an object to all clients:

JSONRPCBridge.getGlobalBridge().registerObject("myObject", myObject);

To export all static methods of a class to all clients:

JSONRPCBridge.getGlobalBridge().registerClass("MyClass", com.example.MyClass.class);

Posted by Igor E. Poteryaev on March 23, 2005 at 02:58 PM MST #

I know it's an old post, but in case you get here take a look at http://jabsorb.org/, the evolution of JSON-rpc

Posted by Raziel on April 18, 2008 at 03:11 PM MDT #

Post a Comment:
  • HTML Syntax: Allowed