Combining SOAP and ORM - Part 2

By Scott Balmos
Posted by Jack Vaughan
In my previous blog entry, we looked at a simple way to start combining SOAP and object relational persistence. In this entry, I expand on the example to show pitfalls with Maps and lazy fetching, and the way I work around them.

Here’s the entities again, with the addition of a Map to the User for a collection of user preferences, along with some additional code in the Group entity. I’ll explain below…
package test;

@Entity
public class User implements Serializable {
    private Long id;
    private String userName;
    private String password;
    private String firstName;
    private String lastName;
    private Map preferences = new HashMap();

    @Id
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getUserName() { return userName; }
    public void setUserName(String userName) { this.userName = userName; }

    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    @CollectionOfElements @XmlJavaTypeAdapter(StringStringMapAdapter.class)
    public Map getPreferences() { return preferences; }
    public void setPreferences(Map preferences) { this.preferences = preferences; } }

package test;

@Entity
public class Group implements Serializable {
    private Long id;
    private String name;
    private List members = new ArrayList();

    @Id
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @OneToMany @XmlTransient
    public List getMembers() { return members; }
    public void setMembers(List members) { this.members = members; }

    @Transient @XmlElement(name = “members”)
    private List getMembers_()
    {
        List vals = new ArrayList(members.size());
        for (User member : members)
        {
            User entry = new User();
            entry.setId(member.getId());
            vals.add(entry);
        }
        return vals;
    }
    private void setMembers_(List members) { this.members = members; } }

So we have a few new things here… In the User class, we have a Map of preferences, with an XmlJavaTypeAdapter pointing to a StringStringMapAdapter class. More on that in a few moments.

Let’s look in the Group class now. We have a few new annotations for the members collection. On the existing getMembers(), we have added XmlTransient. This prevents the XML marshaller in the SOAP engine from returning the full members collection. This is because of lazy fetching, on by default in all mapped collections in JPA.

Lazy fetching keeps the load down on our database servers by not loading all the details of each member entity in a collection. Such as in our Group entity, lazy fetching keeps the database server from having to load more details about the User entities in a group other than just the entity IDs. Other details for each member entity in a collection are retrieved in realtime if they are accessed. Normally this is all well and good. But think about the SOAP XML marshaller. It walks all fields in an object graph. So it will always touch each member in a collection, causing the ORM layer to constantly ask the database to load all details of that member. This completely negates the usefulness of lazy fetching, and can severely degrade your application’s performance.

So in collections that are lazily fetched, I use XML attribute pairing, where the only entity get/set methods available to my SOAP backend application are the original ones, which is within the ORM context of lazy fetching like I want. But now I have a pair of private get/set methods, which is what I want the XML marshaller to use. I mark it with the Transient JPA annotation so the ORM layer doesn’t scream about an unmatched entity field. And I use XmlElement to tell the XML marshaller that this is the get/set method pair I want to use when dealing with that collection. I write the get method so that we build an identical collection to return with member entities that only contain the IDs set.
It doesn’t matter that they’re private, since the XML marshaller uses reflection and ignores method access modifiers.

Now, I will get back a Group entity that I expect, with only a collection of User IDs, just like I would get in a lazily-fetched Group object in my normal Java application. If I wanted more data for the Users, I might have a separate endpoint method that takes a List of IDs, say List getUsersByIDs(List userIDs).

Back to Maps and the User class now… The SOAP spec, oddly, has no base class for any type of key-value Map (whether you call it a Map, Hash, Dictionary, whatever). A few SOAP stacks automatically, in the background, create their own custom Map type. But I’ve lost track of which ones do and which don’t. Most times, they’re incompatible across other stacks.

Here, I use an XmlJavaTypeAdapter to specify a custom XML marshaller / unmarshaller, when dealing with Maps. The code for StringStringMapAdapter is below.
public class StringStringMapAdapter extends XmlAdapter> {
    public Map unmarshal(MapEntry[] mapEntries) throws Exception
    {
        Map map = new HashMap();
        for (MapEntry entry : mapEntries)
        { map.put(entry.getKey(), entry.getValue()); }
        return map;
    }

    public MapEntry[] marshal(Map map) throws Exception
    {
        MapEntry[] values = (MapEntry String>[])Array.newInstance(MapEntry.class, map.size());
        int i = 0;
        for (Map.Entry entry : map.entrySet())
        {
            values[i] = new MapEntry();
            values[i].setKey(entry.getKey());
            values[i].setValue(entry.getValue());
            i++;
        }
        return values;
    }
}
and the code for MapEntry, which is a simple generic custom type for a key-value pair, is below.

public class MapEntry
{
    private K key;
    private V value;

    public K getKey() { return key; }
    public void setKey(K key) { this.key = key; }

    public V getValue() { return value; }
    public void setValue(V value) { this.value = value; } }

XmlAdapter is a base class that deals with XML marshalling and unmarshalling. The first generic type is the XML value type you want to marshal to. The second is the native Java type in your application you want to unmarshal from. Most of it is self-explanatory, after reading my explanation of the attribute pairs above for lazy fetching. I do a little bit of reflective nastiness in marshal(), in order to get around the fact that you can’t directly declare a generic array in Java (e.g. MapEntry[] values = new MapEntry[5] for example).

One annoying part about XmlAdapter when dealing with Maps is the fact that you need to write separate classes for each different key-value type pair. Personally, I have one for Map, one for Map, and a few others.

I seem to remember a bit of rumbling in the JAXB forums on possibly integrating automatic Map marshalling / unmarshalling, to remove the need for custom XmlAdapters. And I’m not sure whether .Net has auto-marshalling for Maps. I write much more Java than C#. I’d be interested to hear what other stacks handle Maps automagically, and how they end up looking in SOAP messages on the wire.

JAX-WS: Deployment Descriptor-free Programming

By Jack Vaughan
The open-source GlassFish J2EE 5 application server allows what may be described as a simplified object component architecture, certainly in comparison to some of its forbearers. Used in conjunction with JAX-WS it supports descriptor free programming, which is welcomed by developers looking for ease of services deployment. We talked recently with Sun’s Arun Gupta about GlassFish, JAX-WS, and how Web service creation can be streamlined. Gupta is a technology evangelist for Web Technologies and Standards at Sun Microsystems, Inc., as well as a charter blogger on TheServerSide Interoperability Blog.

Arun said he strongly believes in descriptor-free programming.

“In the past,” he said, “even experienced developers have found it challenging to write descriptors.” In new scenarios, the descriptors still exist and, if you like, you can bundle them with your application. But not having to write deployment descriptors and focus on your business logic gets you started quickly.

Arun recently posted a blog entry about deploying a service in GlassFish using JDK annotations. It is entitled JAX-WS: Deployment Descriptor-free Programming. A most impressive aspect of the design sample he uses for illustration is that, in his words, “it gives you the ability of going descriptor-free.”

As he puts it: “No deployment descriptors are required if you can live with the reasonable defaults defined by the JAX-WS specification.”

“Glassfish recognizes a class to be a Web service, and uses a default URL to be the end point,” he told us. In his example, that is: http://localhost:8080/Hello/HelloService?wsdl

Related
JAX-WS: Deployment Descriptor-free Programming

Combining ORM and SOAP - Part 1

By Scott Balmos
Posted by Jack Vaughan
In today’s incarnation of the Interop blog, I’ll follow Ted Neward’s lead and give an example of how to combine SOAP with another one of the most widely-used classes of application frameworks - Object/Relation Mapping.

Aside from Web Services, one of the most popular classes of application frameworks deals with object persistence. We all love writing raw SQL just as much as we love writing our own WSDL files, right? So, I’ll give a simple example here with two entity classes and an appropriate SOAP endpoint to use them. Just as much as we love “Hello World” type programs, we’ll show a standard User / Group type setup here, something that easily shows the object relations.

I’ll be writing in JPA for EJB3. If anyone is interested in equivalent C# code, let me know in a comment and I’ll post it up.

First, the entities…

package test;

@Entity
public class User implements Serializable {
    private Long id;
    private String userName;
    private String password;
    private String firstName;
    private String lastName;

    @Id
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getUserName() { return userName; }{
    public void setUserName(String userName) { this.userName = userName;{
}{
{
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password;
}

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName =
firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName;
} }

package test;

@Entity
public class Group implements Serializable {
    private Long id;
    private String name;
    private List members = new ArrayList();

    @Id
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @OneToMany
    public List getMembers() { return members; }
    public void setMembers(List members) { this.members = members;
} }

And now, the SOAP endpoint…

package test;

@WebService
public class TestService
{
    @PersistenceContext private EntityManager em;

    public User getUserById(Long userId)
    {
        User user = em.find(User.class, userID);
        return user;
    }

    public User addUser(String firstName, String lastName, String
userName, String password)
    {
        User user = new User();
        user.setFirstName(firstName);
        user.setLastName(lastName);
        user.setUserName(userName);
        user.setPassword(password);
        em.persist(user);
        return user;
    }

    public Group getGroupById(Long groupId)
    {
        Group group = em.find(Group.class, groupId);
        return group;
    }
}
There are obviously quite a number of other methods that could be created. But these show the general idea. A user entity class has a username, password, first name, and last name. A group entity is basically a collection of users, hence the OneToMany collection mapping annotation. In our endpoint, we use a standard JPA EntityManager to handle everything.

One thing to note is the addUser method, and modification methods in general when combining SOAP and ORM. You’re probably wondering why I didn’t create addUser(User user)? Most times, stub generators will put service stubs and custom type classes with all of the XML annotations in a subpackage, like something.ws. In this case, the entity classes on the client side would be in package test.ws. So if our client tried to pass a User object to addUser(), it would really get a test.ws.User instead of test.User. The test.ws.User class doesn’t have any of the required JPA entity annotations, so the EntityManager would scream at us.

So I tend to have modification methods that pass as parameters either base types, or the entity IDs of entities when creation relations. If I had expanded the SOAP endpoint example, I would’ve added addMemberToGroup(Long groupId, Long userId). Another good thing with this route is that you ensure your client is using a proper entity ID and is only changing the entity field(s) that should be modified. If I had modifyUserPassword(User user, String password), then we certainly know that we should be modifying a password. But the passed in User entity might’ve also had the username, first name, or last name modified without our authorization (or knowledge). In this route, we can do proper data checking before committing the new field values to the entity.

Next time, I’ll expand on the above samples to show two issues that have to be dealt with when using SOAP with Maps, and especially with lazy fetching (a core tenant of object relational persistence).

Web services and interop

A few times on this blog now we have kind of waltzed around these questions: When are Web services a good fit? Where not?

In a recent article, writer Colleen Frye asked just such questions of Forrester analyst John Rymer. Like others, he admits that,  where performance is a key issue, Web services may not be the best option.

For loosely coupled application or component integration, where the interactions can be accomplished through messages rather than direct API calls, Web services may fit the bill, Rymer said. However, for tightly coupled integration or in-process integration, Rymer suggests other options like bridging middleware such as integration servers or Enterprise System Buses [ESBs]; extended J2EE platforms that implement .NET features; and language integration technologies.

The verbosity or latency of Web services - call it what you will - was there at the outset. One is careful to place too much emphasis on that, since hardware historically has had a way of catching up. But you’d antcipate that Web services would be largely frozen out of intense applications such as electronic trading today. How far does that boundary extend?

In a Forrester report last year, Rymer wrote that Web services technologies will eventually become more broadly useful. Binary Web services formats continue to be discussed as an option for in-process integration, but one wonders if they are much further along this year than last. What do you think?

Web services no interop cure - TheServerSide.NET