BT

Writing JEE applications with Grails and Flex

Posted by Maarten Winkels on Nov 03, 2008 |

The Java Platform has evolved into a solid and mature enterprise application platform. One of the signs of a mature application platform is that there are a lot of spin-off techniques and options to integrate with other techniques. This article will go into detail about how to write JEE applications with Grails, a spin-off of traditional JEE application development, and Flex, a different technique that can be used with Java. Both frameworks can be highly productive. Combining the two frameworks holds the promise of building rich internet frontends to J2EE applications while retaining the high productivity.

Grails is originally a web application framework that runs in a JVM using Groovy and well known frameworks like Spring and Hibernate. It relies heavily on the "Convention over Configuration" principle to allow for very fast application development. The addition of Groovy with its many dynamic features makes the application framework extremely powerful in terms of defining common behavior between components. The plug-in architecture that Grails uses makes integrating with other frameworks and reusing functionality between applications very easy.

Flex is a RIA development kit that creates SWF applications that run in the FlashPlayer. It is a new version of the Flash development kit from Adobe (previously MacroMedia). In addition to having a rich set of widgets and a powerful language to glue these widgets together, it also has some advanced communication solutions that make developing distributed applications a lot easier. It uses two types of syntax: MXML and ActionScript. MXML is a XML based syntax that is used to define the buildup of the user interface from generic components. ActionScript is used to define dynamic behaviors on these components.

Integrating Grails and Flex - The problems

When combining two frameworks that are built upon such different foundations as Grails and Flex, a couple of issues arise that have mainly to do with communication:

  1. How do components from one framework find the right components in the other framework to communicate with?
    Grails is in essence a web application framework that runs in a JVM on the server. Flex is a RIA platform that has a client and a (thin) server component. The server component is deployed as a web application. The integration between the two frameworks thus takes place inside a web application container.
    Communication, initiated by a user through the Flex UI, must reach a Grails component to invoke some business logic. How can the Flex UI component reach the correct Grails component?
  2. How is data translated between the frameworks?
    Flex uses ActionScript for data representation. Grails uses Java and Groovy objects. The ActionScript objects that a Flex UI sends to the server should be translated into meaningful application dependant data structures. How can this be done?
  3. How are changes made by a certain user communicated to other users using the application?
    Although this is a general problem for multi-user applications, the usage of two different frameworks makes finding the solution more of a challenge. Changes are made in the Grails application (initiated by user actions in the Flex UI) and should be communicated to a number of users through their Flex UI. How can this be accomplished?

The next three chapters will discuss the above questions in more detail and try to formulate answers using Grails and Flex.

Integration - Finding a target for your message

How do components from one framework find the right components in the other framework to communicate with?

When applied to Grails and Flex, this question is about how Flex components can find the right Grails components to request data or execute an operation on behalf of the user. To get better insight into how this problem can be solved, we'll first take a closer look at the communication subsystem of Flex.

Client-Server communication in Flex

The communication subsystem in Flex can be divided into a client and a server part. The client part contains components that allow the application to send or receive messages, for example the RemoteObject or the Consumer components. These components are associated with specific "Service" objects in the server part, for example the RemotingService and the MessagingService. The combination of a client component with its associated service component supports a typical communication pattern. Using Consumer, Producers and the MessagingService for example, allow the application to use a Publish-Subscribe mechanism for communication.

Communication between client and server goes through a Channel. There are several implementations of Channels. The most important are the AMFChannel and the RTMPChannel. The AMFChannel is based on HTTP and thus on request-response architecture. This channel can be used with the MessagingService to support Publish-Subscribe. In this combination request are done through the channel periodically to fetch new messages that have been published. More efficient in this setting is the RTMPChannel, which supports an open connection between client and server based on TCP/IP. In this manner it allows immediate sending and receiving of messages in both directions. BlazeDS, the free open-source implementation of Flex by Adobe, unfortunately does not contain an implementation of the RTMPChannel.

The most important parts of the communication infrastructure of Flex are the Destinations. These are server-side endpoints of communication channels. A service provides a Destination and client components attach to the service through a Destination. Messages can be sent to a Destination and received from a Destination by attached client components. Destinations can be created by Factories.

Remote exposure in Grails: Services

How should Flex' complex communication infrastructure be combined with Grails? Grails recognizes several types of objects: domain objects, controllers, views and services. A service is in Grails an object that exposes several functions or services through external communication channels, like for example HTTP. In terms of Flex a service corresponds with a Destination.

This is exactly the solution that the flex-plugin for Grails provides. All services in Grails that are marked for exposure to Flex, will be registered as Destinations in the Flex framework. Grails uses a special RemotingService configured in Flex to which all marked services will be added by a specific Factory. This Factory will locate the corresponding service in the Spring context that Grails uses. The configuration for all this can be found in the services-config.xml file that the flex-plugin for Grails copies to the correct location.

class UserService {
  static expose = ['flex-remoting']
  def List all() {
    User.createCriteria().listDistinct {}
  }
  def Object get(id) {
    User.get(id);
  }
  def List update(User entity) throws BindException {
    entity.merge();
    if (entity.errors.hasErrors()) {
      throw new BindException(entity.errors);
    }
    all();
  }
  def List remove(User entity) {
    entity.delete();
    all();
  }
}

This configuration exposes the UserService to RemoteObjects in a flex client. The following MXML fragment shows how this can be used. The destination of the RemoteObject is "userService", which is the service name of the targeted object in Grails. All methods on the service object have become remote operations. These operations can be used from ActionScript as normal methods and results or errors will be handled like normal ActionScript events.

...
  <mx:RemoteObject id="service" destination="userService">
    <mx:operation name="all" result="setList(event.message.body)"/>
    <mx:operation name="get" result="setSelected(event.message.body)"/>
    <mx:operation name="update"/>
    <mx:operation name="remove"/>
  </mx:RemoteObject>
...

Conclusion

The solution that the flex-plugin for Grails provides for the problem of integration is elegant. It is very easy to use and almost automatic. In the spirit of Convention-over-Configuration a naming convention is used when Destinations are dynamically added to the Flex configuration.

Data conversion

How is data (in this case Java and ActionScript objects) translated between the frameworks?

To analyze this problem it is important to realize where the two frameworks touch. Flex consist of a Java component (on the web server) and an ActionScript component (on the client). The boundary between Grails and Flex is thus located on the web server and is in fact a Java application on both sides.

Flex' Java component is focused solely on communication to Flex clients. The AMF protocol is used for this data communication and is based on ActionScript objects. The Java code in the server component translates the data to ActionScript objects is and serializes them over the channel. Flex supports primitive and standard complex Java types (e.g. Date or Collection) out of the box. Since ActionScript is a dynamic language, random objects structures are also supported. The fields of a Java object are converted to dynamic properties on an ActionScript object. Converting these none-typed ActionScript objects back to Groovy domain objects is less straight forward. By default a Map is created, in which properties are stored as key-value pars.

By creating ActionScript classes that have the same properties as the Groovy domain objects and linking them by an annotation, Flex can make the conversion even more smoothly. Below an example of such a Groovy-ActionScript couple is shown.

Groovy ActionScript
class User implements Serializable {
    String username
    String password
    String displayName
}
[RemoteClass(alias="User")]
public class User {
  public var id:*
  public var version:*
  public var username:String;
  public var password:String = "";
  public var displayName:String;


  public function toString():String {
    return displayName;
  } 
}

The "RemoteClass" annotation links the ActionScript class to the Java (or Groovy) class that is indicated with the alias property. This property should contain the fully qualified class name. In Grails domain classes are generally added to the default package. All fields from the Grails class are copied to the ActionScript class. The names should match exactly. The "id" and "version" fields that are added dynamically by Grails to every domain class should also be added, to retain this information during communication with the client.

Conclusion

The solution that Flex offers for data conversion with Java (or Groovy) leads to a lot of code duplication. Every domain class should be defined twice, once in Groovy (or Java) and once in ActionScript. This offers the possibility to add client specific code, e.g. code that is concerned with displaying the object, only to the ActionScript code. It also enables editors to offer code completion for both languages. The usage of annotations for configuration is very convenient.

Multiple Users

How are changes made by a certain user communicated to other users using the application?

In an application that supports multiple users at the same time, one of the challenges is to communicate changes made by one user to the shared data to the other users. For the other users this can be seen as server initiated communication.

When communicating from a single central point (server) to many receivers (clients) it is often helpful to use a publish-subscribe technique. With such a technique clients register (subscribe) with a server. They will be notified when an interesting message is published to the server.

Since Java can be used from Grails JMS can be used. JMS is the Java standard for messaging between applications and it supports publish-subscribe. Flex has its own messaging component, that support publish-subscribe, but it is also possible to integrate with JMS through an adapter.

Configuring JMS in Grails

As for most standards there is a jms-plugin for Grails, that adds a number of useful methods for sending messages to JMS destinations to all controller and service classes. These methods can now be used from the UserService (as described in the previous chapter) to send updates to all clients when a change occurs through JMS.

class UserService {
  ...
  def List update(User entity) throws  BindException {
    entity.merge(flush:true );
    if  (entity.errors.hasErrors()) {
      throw new BindException(entity.errors)
    }
    sendUpdate();
    all();
  }
  def List remove(User entity) {
    entity.delete(flush:true );
    sendUpdate();
    all();
  }
  private def void sendUpdate() {
    try  {
      sendPubSubJMSMessage("tpc",all(),[type:"User"]);
    } catch (Exception e) {
      log.error("Sending updates failed.", e);
    }
  }
}

The service can decide exactly what message should be sent when. Whenever a client updates or removes data, a message is sent containing the complete list of data items. The data is sent to the specified topic, in this case "tpc". Any receiver that is registered for this topic will receive the new data. The type of objects in the list (in this case "User") is added as metadata to the message, to enable receivers to indicate their interest in a specific type of data when registering with the server.

To be able to use JMS in the Grails application, a JMS provider implementation needs to be made available. There is a free open-source implementation available from Apache that can be easily configured from a Grails application. By adding the ApacheMQ library to the lib directory of the Grails application and adding the fragment below to the resources.xml file in the conf/spring directory the connection factory is ready for use.

...
  <bean id="connectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"
/> </bean> </property> </bean> ...

Receiving JMS messages in Flex

The configuration for flex currently only contains a RemotingService that supports request-response style communication that is used to communicate with the UserService. This service was added by the flex-plugin for Grails. In addition we now need a MessagingService to support publish-subscribe style communication.

...
    <service id="message-service" class="flex.messaging.services.MessageService" messageTypes="flex.messaging.messages.AsyncMessage">

<adapters>
<adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter" default="true"/>
</adapters> <destination id="tpc">
<properties>
<jms>
<message-type>javax.jms.ObjectMessage</message-type> <connection-factory>ConnectionFactory</connection-factory> <destination-jndi-name>tpc</destination-jndi-name> <delivery-mode>NON_PERSISTENT</delivery-mode> <message-priority>DEFAULT_PRIORITY</message-priority> <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode> <transacted-sessions>false</transacted-sessions> <initial-context-environment> <property> <name>Context.PROVIDER_URL</name> <value>vm://localhost</value> </property> <property> <name>Context.INITIAL_CONTEXT_FACTORY</name> <value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value> </property> <property> <name>topic.tpc</name> <value>tpc</value> </property>
</initial-context-environment>
</jms>
</properties>
</destination>

</service>
...

To the services-config.xml we add the fragment below that contains a new MessagingService with a JMSAdapter. This adaptor links destinations in the service to JMS resources. The service also contains the configuration for a destination that consumers in the flex code can subscribe to. The destination contains a number of JMS specific configurations. Most are well-known JMS properties. The "topic.tpc" property in the initial-context-environment is a custom ActiveMQ property that will register a topic with JNDI name "tpc" in the context.

...
  <mx:Consumer destination="tpc" selector="type = 'User'"
    message="setList(event.message.body)"/>
...

The Flex client code is very simple. A Consumer component receives the messages that are sent to the specified destination that comply with the selector. In this case we use the selector to specify that this Consumer is interested in messages with the "type" metadata property set to "User". Whenever a message is received the content of the message, which should be a list of User-objects is placed in an internal list that can be displayed. The handling of the content of the message is exactly the same as with the return value of the "all"-operation on the RemoteObject.

Conclusion

The solution for communicating changes to multiple users with Grails and Flex can be built completely from standard components. The number of components involved makes the configuration and implementation rather complex. When configured correctly, using this solution is quite straight forward.

Combining the solutions

Looking back at the solutions in the last three chapters, there seems to be a possibility to combine them into a generic solution for communicating domain state between client and server in a Flex/Grails application. In this chapter we will look at what such a generic solution might look like.

Generalizing the server side code

The code that runs on the server side for the solutions to problems 1 and 3 are already combined in a single Groovy service. This service is now specific for the User domain class. Using Groovy, being a dynamic language, it is fairly easy to generalize this service to be applicable to all domain classes.

import org.codehaus.groovy.grails.commons.ApplicationHolder

class CrudService {
  static expose = ['flex-remoting']

  def List all(String domainType) {
    clazz(domainType).createCriteria().listDistinct {}
  }

  def Object get(String domainType, id) {
    clazz(domainType).get(id)
  }

  def List update(String domainType, Object entity)
      throws BindException {
    entity.merge(deepValidate:false, flush:true)
    if (entity.errors.hasErrors()) {
      throw new BindException(entity.errors)
    }
    sendUpdate(domainType);
    all(domainType);
  }

  def List remove(String domainType, Object entity) {
    entity.delete(flush:true);
    sendUpdate(domainType);
    all(domainType);

  }
  private def Class clazz(className) {
    return ApplicationHolder.application.getClassForName(className);
  }

  private def void sendUpdate(String domainType) {
    try {
      sendPubSubJMSMessage("tpc", all(domainType), [type:domainType]);
    } catch (Exception e) {
      log.error("Sending updates failed.", e);
    }
  }
}

The main trick to achieve this is to let the client decide which domain type to return. To this purpose a parameter is introduced to all services that will identify the domain type for the server. The class name of the domain type is an obvious choice to use for this parameter. The resulting service will provide C(reate)R(etrieve)U(pdate)D(elete) operations on all domain objects and can thus be called a CrudService.

The CrudService will send updates to a JMS topic whenever a change is made. This update consists of the complete list of domain object currently known to the application. To allow clients to easily decide which updates are interesting to them, the name of the class of the domain type is added as metadata to the message.

The client code

The ActionScript code on the client side from solution 1 and 3 can also be combined in a single class. An instance of this class can then be used to manage the collection of all instances of a certain domain type on the client side.

public class DomainInstancesManager
{
  private var domainType : String;
  public function EntityManager(domainType : String, destination : String) {
    this.domainType = domainType;
    initializeRemoteObject();
    initializeConsumer(destination);
  }

  private var  _list : ArrayCollection = new ArrayCollection();
  public function get list () : ArrayCollection {
    return _list;
  }
  private function setList(list : *) : void {
    _list.removeAll();
    for each (var o : * in list) {
      _list.addItem(o);
    }
  }

  internal static function defaultFault(error : FaultEvent) : void {
    Alert.show("Error while communicating with server: " + error.fault.faultString);
  }
  ...
}

The ActionScript implementation of the clients consists basically of two components: The RemoteObject that facilitates request-response conversations and the Consumer that facilitates producer-subscriber conversations. In the previous chapters these objects were initialized from MXML code, but they can also be created in ActionScript. The code fragment above shows the common structures that both components use: The list that will contain the instances and error handling. The list with instances will be updated by messages coming through either of the communication components.

  ...
  private var consumer : Consumer;
  private function initializeConsumer(destination : String) : void {
    this.consumer = new Consumer();
    this.consumer.destination = destination;
    this.consumer.selector = "type ='" + domainType + "'";
    this.consumer.addEventListener(MessageEvent.MESSAGE, setListFromMessage);
    this.consumer.subscribe();
  }

  private function setListFromMessage(e : MessageEvent) : void {
    setList(e.message.body);
  }
...

This code fragment shows how the Consumer is constructed from ActionScript, that will be used to receive messages that are pushed from the server. The selector property on the Consumer is set to only receive those messages that contain the specified domainType as type in the metadata. Whenever such a message is received, the event handler will be invoked and this will update the list.

The next code fragments is concerned with setting up the RemoteObject as endpoint of the request-response style communication. All necessary operations are added to the operations property on the RemoteObject, so they can be easily invoked.

...
private var service : RemoteObject;
private var getOperation : Operation = new Operation();
public function initializeRemoteObject() {
	this.service = new RemoteObject("crudService");

	var operations:Object = new  Object();
	operations["all"] =  new  Operation();
	operations["all"].addEventListener(ResultEvent.RESULT, setListFromInvocation);
	operations["get"] = getOperation
	operations["remove"] = new  Operation()
	operations["remove"].addEventListener(ResultEvent.RESULT, setListFromInvocation);
	operations["update"] = new  Operation()
	operations["update"].addEventListener(ResultEvent.RESULT, setListFromInvocation);
	this .service.operations = operations;
	this .service.addEventListener(FaultEvent.FAULT, defaultFault);

	// Get the instances from the server.
	this.service.all(domainType);
	}

public function get(id : *, callback : Function) : void {
	var future: AsyncToken = getOperation.send(domainType, id);
	future.addResponder(new CallbackResponder(callback));
}

public function update(entity : Object) : void {
	service.update(domainType, entity);
}

public function remove(entity : Object) : void {
	service.remove(domainType, entity);
}

private function setListFromInvocation(e : ResultEvent) : void {
	setList(e.message.body);
}
...

Most methods simply delegate to one of the operations of the service. All these operations are non blocking and asynchronous. Whenever the service returns, the return value is handled by the registered eventhandler (setListFromInvocation), which will upate the list. The 'getOperation' is a bit of an exception, since the result is used in multiple places. To get the result a CallbackResponder must be registered for each call to handle the result. The responder will invoke a Function with the content of the message that was received.

import  mx.rpc.IResponder;
import  mx.rpc.events.ResultEvent;

public  class CallbackResponder implements  IResponder {
  private  var callback : Function;
  function CallbackResponder(callback : Function) {
    this .callback = callback;
  }

  public  function result(data : Object) : void  {
    callback(ResultEvent(data).message.body);
  }

  public  function fault(info : Object) : void  {
    DomainInstancesManager.defaultFault(info);
  }
}

Using the generic package

So how would you use this generic package? Let's look at an example of managing the instances of User objects as we have seen in the second solution. The MXML code below defines a PopUpDialog which can be used to edit the details of Users in the system. The Dialog will look like the image on the left. The instance variable 'manager' is initialized to be a DomainInstanceManager for the User domain type. The window contains a list of all users that is bound to the list property of this manager. It displays the displayName of the user.

<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:users="users.*" title="User Manager">
  <mx:Script>
    <![CDATA[
      import crud.DomainInstancesManager;
      import mx.managers.PopUpManager;
      [Bindable]
      private var  manager : DomainInstancesManager = new DomainInstancesManager("User", "tpc");

      private function resetForm() : void {
        selectedUser = new User();
        secondPasswordInput.text = "";
      }

      private function  setSelected(o : Object) : void
      {
        selectedUser = User(o);
        secondPasswordInput.text = selectedUser.password;
      }
    ]]>
  </mx:Script>
  <users:User id="selectedUser"
    displayName="{displayNameInput.text}"
    username="{usernameInput.text}"
    password="{passwordInput.text}"/>
  <mx:List height="100%" width="200" dataProvider="{manager.list}" labelField="displayName"
    itemClick="manager.get(User(event.currentTarget.selectedItem).id, setSelected)"/>
  <mx:VBox height="100%" horizontalAlign="right">
    <mx:Form>
      <mx:FormItem label="Display Name">
        <mx:TextInput id="displayNameInput" text="{selectedUser.displayName}"/>
      </mx:FormItem>
<mx:FormItem
label="User Name"> <mx:TextInput id="usernameInput" text="{selectedUser.username}"/> </mx:FormItem>
<mx:FormItem
label="Password"> <mx:TextInput id="passwordInput" text="{selectedUser.password}" displayAsPassword="true"/> </mx:FormItem>
<mx:FormItem
label="Password"> <mx:TextInput id="secondPasswordInput" text="" displayAsPassword="true"/> </mx:FormItem>
</mx:Form>
<mx:HBox
width="100%"> <mx:Button label="New User" click="{resetForm()}"/> <mx:Button label="Update User" click="{manager.update(selectedUser);resetForm()}"/> <mx:Button label="Remove User" click="{manager.remove(selectedUser);resetForm()}"/> </mx:HBox>
<mx:Button
label="Close" click="PopUpManager.removePopUp(this)"/> </mx:VBox>
</mx:TitleWindow>

Whenever an item in the list is clicked, the associated user object is retrieved from the server and stored in the 'selectedUser' property of the window. This property is defined in MXML so it easier to use binding with the fields in the form. The properties of the 'selectedUser' property and the input fields on the form are 'bi-directionally' bound to each other, so changed in the value of the 'selectedUser' property (by events coming from the server) are reflected in the input fields and changes in the values of the fields (by user input) are reflected in the value of the 'selectedUser' property. The buttons on the window are linked to the methods on the manager, using the 'selectedUser' property as parameter. The results of the method calls will be reflected in the list that is maintained by the manager and in the list on the window, since it is bound to that.

Remarks

It is important to notice that using this package you'll maintain a list on the client side of all objects of a certain type in the system. For certain references data and data of which you expect to have a limited amount of instances, this fine. For other types of data it might not be required or even feasible to maintain a complete list. In these cases the same principles maybe applied to a subset of the complete list.

One interesting point is that whenever a client changes data (either he saves, updates or removes a domain object), he'll get a response containing the new list. He'll also receive the message that all other users get containing the updated list. A client thus receives two updates for every change he makes. The first (the response to his request) can be dropped, but it has been added to the system, since the direct response is often more timely then the message through JMS.

Another thing worth mentioning is that there might be concurrency problems in this model, since messages containing updates (in this case the full list) come through different channels. Messages might arrive late and later messages might have arrived before them. This would mean the client is showing stale data. One way to solve this is to include a sequence number in the messages and check this number when receiving a message against the latest message that was received.

Conclusion

The generic package wraps up the solutions found in the previous chapters in an easy to use format.

The solutions shown in this article provide a solid foundation for developing JEE applications using Flex and Grails. JEE development with these toolkits can be faster, more agile and, maybe most important, more fun!

About the Author

Maarten Winkels is a Software Engineer and Consultant with more than 5 years of experience in Java and JEE development. He has recently moved from the Netherlands to India, to help facilitate the Distributed Agile process that Xebia offers. Xebia is a company is specialized in Java technology, Agile offshoring & projects, Agile consultancy and training, IT Architecture and Auditing. See http://www.xebia.com/.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Good one by Chao Liu

Good job Maarten.

Good Article by Aravind Radhakrishnan

You made good understanding using flex in j2ee

Why proprietary flex? by Gene De Lisa

So how about JavaFX instead?

Re: Why proprietary flex? by Jason Hurt

Please explain to me how Flex is more proprietary than JavaFX?

Great article, by the way.

Lazy initialization by danilo marques

Nice post!
But... what about the lazyInitializationExeptions that always happens using Flex and Grails!?

Sending Messages with Selectors by Ricardo Aguas

Hello! How works these plugins when I try send messages with selectors? Someone have a example?

any working example will be great by rags lin

Can any one provide and link to a working example?
A working example will make life easier for me and others too.

sendPubSubJMSMessage("tpc", all(domainType), [type:domainType]); by rags lin

I see a big problem here.. There are 3 parameters are passed to function sendPubSubJMSMessage

sendPubSubJMSMessage("tpc", all(domainType), [type:domainType]);

, whereas it accepts only 2 parameters. Am I wrong?

Re: Lazy initialization by Jim Shingler

Using the SessionInViewFilter will solve the lazy initialization problem

Re: Lazy initialization by Tom Gilmour

I've done exhaustive research on this and almost gave up. But I did figure it out after looking at many posts and hibernate blogs.

Say you have a service exposed to flex, with a simple method:

def getUserList(){
User.list()
}

This will throw the dreaded LazyInitialization exception because it's trying to render the list results outside of the hibernate session.

A quick and dirty solution would be to package it up to a non-hibernate bound object and return that instead:

def getUserList(){
def outList = new ArrayList()
def userList = User.list()
for(thisUser in userList){
outList.push([firstName:thisUser.firstName, lastName:thisUser.lastName])

}
return outList
}

I'm sure there are more elegant ways of writing this code, but this will avoid the LazyInitialization exception.

If anyone else has a better solution to this, please share, as I've scoured the internet looking for why this was happening.

Re: Lazy initialization by Tom Gilmour

I tried this, but it didn't work.

Has this SessionInViewFilter solution worked for anyone?

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

11 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT