PDA

View Full Version : Server-client data transfer (RPC, POJOs and Data Transfer Objects)



zaccret
23 May 2008, 5:59 AM
For server-client data transfer, GWT RPC is great and is sufficient for most cases.
If your domain objects are really simple (POJOs) and depends only on JRE types or other domain objects, that's great !! You just have to add the domain objects to the GWT source path, make them Serializable and so they can be used as return types or parameter types in your RPC calls.

If not (you cannot put all the whole world Java classes in your GWT source path or you don't want for some reason - memory usage on client side, for example ?), here comes the issue. As far as I know, here are the solutions :
if you use Hibernate, you can use hibernate4gwt. What I don't like here : your domain objects have to EXTEND LazyGWTPojo.
you can write Data Transfer Objects (DTO) : you write java classes in GWT source path containing all data need by your services. In most cases, these classes will look like clones of your domain objects (code redundancy).
you can use the GXT BaseModel and put the properties you want using the set(String,Object) method (but this is almost like DTOs).
you serialize your data (your domain objects) in JSON format (no more Java classes to write, but you have to parse JSON on the client side). For that, you can use a framework like Flexjson (it has annotation support and I think it has Hibernate support) or XStream.
I'd like to know which solution you use and why ? What is your preference ? Are there any other solutions ?

Thanks.

zaccret
23 May 2008, 6:06 AM
create your own annotation-based framework (less flexible but less code to write - except the framework)
Actually, Flexjson seems to already handle annotations

joshb
23 May 2008, 7:08 AM
I've been experimenting with some custom solutions to this problem. Like you, I didn't want redundant Client-side representations, and I wanted something that would easily be used by GXT's data models.

What I've come up with thus far is a 'ServerModel' class which has one static method "TransformObject" which takes two parameters:

Object o - the Object to Transform
String[] s - A list of strings representing the field names to grab from the object and stick in the DataModel. I've set it up to recurse through sub-objects as well, so an example would be:


BaseModelData m = ServerModel.transformObject(u, new String[] { "nameFirst", "nameLast", "email", "parent.email" } );


where U is a user User object with a field 'parent' which is also a User object (as well as a nameFirst etc... property)

This allows me to select only the fields I need for a given operation saving memory/transfer speeds. Obviously I should have a "transformObjects" method that would take a list returned from a Hibernate query.

So far this looks like something that will at least give me the short term efficiency gains I need while avoiding a lot of redundant code.

Thoughts?

damir222
23 May 2008, 7:40 AM
Hi,

there doesn't seem to be any satisfactory solution for now. I also use something like joshb's aproach for the time beeing.

Don't know what darell thinks, this is very important in the long term as nobody wants to use DTO's or equvalent.

Could GWT compiler be used to create DTO's from annotated fields in the domain POJOs (perhaps with package-prefix replacement).

Damir

maku
24 May 2008, 3:17 AM
HI,

I'm using pure JPA Entity classes also on the GWT client. From the hibernate4gwt project I use only the "detaching" mechanism to change the hibernate specific stuff from my objects.

My entity classes have no dependency to the hibernate4gwt.

The detaching happens on one place (AOP -> with gwt-sl)


Works fine until now.

Regards

Martin

connysvensson
26 May 2008, 1:35 AM
We have implemented our own DataItem transfer objects, which pretty much implements a map. On the client side they're turned into BaseModels (or subclasses thereof). We can of course also send Lists of these items.

I'm interested in hibernate4gwt as we're using Seam on the backend. Maku can you provides some more details about how you use it. It sounds just like what we would like to have.

maku
26 May 2008, 4:02 AM
We have implemented our own DataItem transfer objects, which pretty much implements a map. On the client side they're turned into BaseModels (or subclasses thereof). We can of course also send Lists of these items.

I'm interested in hibernate4gwt as we're using Seam on the backend. Maku can you provides some more details about how you use it. It sounds just like what we would like to have.

As I mentioned in my post I use gwt-sl (http://gwt-widget.sourceforge.net/) to use spring and dependency injection and AOP for a declarative approach for my RPC services.

In my case I extend org.gwtwidgets.server.spring.GWTRPCServiceExporter from gwt-sl project and override the method "invokeMethodOnService".
An instance of this class works a central entry point for every RPC service call (AOP).
When the work in the backend is done I "detach" the Hibernate object instances (using the net.sf.hibernate4gwt.core.LazyKiller class from hibernate4gwt)

e.g.

public class GwtServiceHandler extends GWTRPCServiceExporter {

@Override
public String invokeMethodOnService(Object service, Method targetMethod, Object[] targetParameters, RPCRequest rpcRequest) throws Exception {

...

Object result = targetMethod.invoke(service, targetParameters);
if(result!=null) {

// lazy hibernate associations have to be detached
result=lazyKiller.detach(result);
}
String encodedResult = RPC.encodeResponseForSuccess(rpcRequest.getMethod(), result, rpcRequest.getSerializationPolicy());
...
}


...
}

I don't know if this is the best approach. But it seems one where you have no dependencies to hibernate4gwt in your entity classes.

zaccret
28 May 2008, 8:39 AM
I'm using pure JPA Entity classes also on the GWT client. From the hibernate4gwt project I use only the "detaching" mechanism to change the hibernate specific stuff from my objects.

My entity classes have no dependency to the hibernate4gwt.


So you put your entity classes in the GWT source path ? I guess your entity classes don't depend on other libraries. I tried to put my domain objects in the source path but some depend on other libraries (most or all cases, it is just an import for an annotation) and they are written in Java 6 so I would have to make a lot of modifications.

maku
28 May 2008, 10:16 PM
So you put your entity classes in the GWT source path ? I guess your entity classes don't depend on other libraries. I tried to put my domain objects in the source path but some depend on other libraries (most or all cases, it is just an import for an annotation) and they are written in Java 6 so I would have to make a lot of modifications.

Yes I use only JPA and hibernate annotations. And yes I try not using other libs directly in the entities which could be seen as pragmatically way to be able to use the entity classes also in GWT withoud the need for DTO's.

zaccret
28 May 2008, 10:18 PM
The annotations don't cause compilation errors with GWT ? You don't import them ?

maku
29 May 2008, 12:42 AM
The annotations don't cause compilation errors with GWT ? You don't import them ?

I think hibernate4gwt does the magic (the hibernate4gwt archive contains the annotation definition in it's emul directory)

Grandiosa
29 May 2008, 2:51 AM
Thanks for sharing your solution Maku. I was thinking about an extension to hibernate4gwt for Ext GWT, but I didn't realize it could be done that simple...

connysvensson
2 Jun 2008, 4:14 AM
As I mentioned in my post I use gwt-sl (http://gwt-widget.sourceforge.net/) to use spring and dependency injection and AOP for a declarative approach for my RPC services.

In my case I extend org.gwtwidgets.server.spring.GWTRPCServiceExporter from gwt-sl project and override the method "invokeMethodOnService".
An instance of this class works a central entry point for every RPC service call (AOP).
When the work in the backend is done I "detach" the Hibernate object instances (using the net.sf.hibernate4gwt.core.LazyKiller class from hibernate4gwt)

e.g.

public class GwtServiceHandler extends GWTRPCServiceExporter {

@Override
public String invokeMethodOnService(Object service, Method targetMethod, Object[] targetParameters, RPCRequest rpcRequest) throws Exception {

...

Object result = targetMethod.invoke(service, targetParameters);
if(result!=null) {

// lazy hibernate associations have to be detached
result=lazyKiller.detach(result);
}
String encodedResult = RPC.encodeResponseForSuccess(rpcRequest.getMethod(), result, rpcRequest.getSerializationPolicy());
...
}


...
}

I don't know if this is the best approach. But it seems one where you have no dependencies to hibernate4gwt in your entity classes.

This is pretty much what I've been trying, but using Seam on the backend and with one central dispatcher that all remote calls goes thru. I'm calling detach with lazy killer instantiated with null class mapper and the HibernateUtil. How do you instantiate it?
I get the following error:

com.google.gwt.dev.shell.HostedModeException: Something other than an int was returned from JSNI method '@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::readInt()': attempt to use JavaScript 'undefined' as a value, expected int

On the server side all properties are set in the entity. Have you had any problems in the serialization process? I don't get any further as it's pretty tough to debug the GWT framework.
I'm using plain JPA entities that only implements Serializable, no hibernate4gwt stuff. Do you call GWT.create on you entity class in you onModuleLoaded method, or is this needed at all? I can't find a simple example of plain JPA entities with GWT 1.5 (M2) and hibernate 1.04 (M2). What mode should hibernate4gwt operate in? Proxy or stateless, or any other?
I don't want to use the BeanManager as Seam already handles the enityManager and all other stuff I need. I only want the LayKiller functionality to detach and attach. I think this is what you're doing as well, right?

connysvensson
2 Jun 2008, 5:32 AM
I tested again with a supersimple entity just to rule out any entity related problems. SAme problem. I don't even have an integer in the entity, still the StreamReader tries to read an int. Something is wrong somewhere. Any pointers?

Here is the entity I'm trying to send via RPC:

@Entity
@Table(name = "T_TEST")
public class Test implements Serializable {

public static final long serialVersionUID = 3574324321429348563L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Long id;

@Column(name = "name")
private String name;

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;
}

}

maku
2 Jun 2008, 10:01 PM
This is pretty much what I've been trying, but using Seam on the backend and with one central dispatcher that all remote calls goes thru. I'm calling detach with lazy killer instantiated with null class mapper and the HibernateUtil. How do you instantiate it?
I get the following error:

com.google.gwt.dev.shell.HostedModeException: Something other than an int was returned from JSNI method '@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::readInt()': attempt to use JavaScript 'undefined' as a value, expected int

On the server side all properties are set in the entity. Have you had any problems in the serialization process? I don't get any further as it's pretty tough to debug the GWT framework.
I'm using plain JPA entities that only implements Serializable, no hibernate4gwt stuff. Do you call GWT.create on you entity class in you onModuleLoaded method, or is this needed at all? I can't find a simple example of plain JPA entities with GWT 1.5 (M2) and hibernate 1.04 (M2). What mode should hibernate4gwt operate in? Proxy or stateless, or any other?
I don't want to use the BeanManager as Seam already handles the enityManager and all other stuff I need. I only want the LayKiller functionality to detach and attach. I think this is what you're doing as well, right?

I work with noserver mode and a selfmanaged tomcat instance. The whole detaching stuff is only necessary in the backend part. One thing is that I've to use some other gwt libs to emulate certain datatypes like BigDecimal (but when the datatype is a problem you get exceptions in context with serializing stuff)
hibernate4gwt is use only used for detaching (LazyKiller) and that annotations and so on can be resolved.
I've also NO inheriting in my modul definition (like <inherits name='net.sf.hibernate4gwt.Hibernate4Gwt'/>)

In the initializing phase of my app I take the EntityManagerFactory from my Spring config and set some hibernate4gwt stuff :




HibernateBeanManager.getInstance().setEntityManagerFactory((EntityManagerFactory) context.getBean("entityManagerFactory"));
GwtServiceHandler.initLazyKiller(HibernateBeanManager.getInstance().getPersistenceUtil());



and in GwtServiceHandler


private static LazyKiller lazyKiller;
...
public static void initLazyKiller(IPersistenceUtil persistenceUtil) {
lazyKiller=new LazyKiller(null,persistenceUtil);
}

connysvensson
3 Jun 2008, 1:19 AM
I updated my whole stack to RC1 (GWT, EXT-GWT and hibernate4gwt) hoping that it was a bug somewhere that had been fixed. But no such luck. I see that Google has changed the error message for the exception I'm getting but it's the same problem.

"com.google.gwt.dev.shell.HostedModeException: Expected primitive type int; actual value was undefined"

If you look at my Entity definition above I have no int defined in there. You said you had some conversion of BigDecimals and such. Can you please elaborate on that.

I removed the inheritance of the hibernate4gwt module, no difference. This is the code I have in my dispatcher on the server side (Component.getInstance is a Seam framework thing...):

if (lazyKiller == null) {
HibernateSessionFactory sessionFactory = (HibernateSessionFactory) Component.getInstance(HibernateSessionFactory.class); HibernateUtil.getInstance().setSessionFactory(sessionFactory.getSessionFactory());
lazyKiller = new LazyKiller(null, HibernateUtil.getInstance());
}

Test entity = ((RpcEntityResult) result).getEntity();
Test clonedCopy = (Test) lazyKiller.detach(entity);
((RpcEntityResult) result).setEntity(clonedCopy);

gslender
3 Jun 2008, 2:20 AM
have you tried taking out the Long ?

maku
3 Jun 2008, 3:43 AM
I updated my whole stack to RC1 (GWT, EXT-GWT and hibernate4gwt) hoping that it was a bug somewhere that had been fixed. But no such luck. I see that Google has changed the error message for the exception I'm getting but it's the same problem.

"com.google.gwt.dev.shell.HostedModeException: Expected primitive type int; actual value was undefined"

If you look at my Entity definition above I have no int defined in there. You said you had some conversion of BigDecimals and such. Can you please elaborate on that.

I removed the inheritance of the hibernate4gwt module, no difference. This is the code I have in my dispatcher on the server side (Component.getInstance is a Seam framework thing...):

if (lazyKiller == null) {
HibernateSessionFactory sessionFactory = (HibernateSessionFactory) Component.getInstance(HibernateSessionFactory.class); HibernateUtil.getInstance().setSessionFactory(sessionFactory.getSessionFactory());
lazyKiller = new LazyKiller(null, HibernateUtil.getInstance());
}

Test entity = ((RpcEntityResult) result).getEntity();
Test clonedCopy = (Test) lazyKiller.detach(entity);
((RpcEntityResult) result).setEntity(clonedCopy);

For testing, try to implement the marker interface com.google.gwt.user.client.rpc.IsSerializable in your entity class to eliminating potential serializiation errors (i think when you only implement Serializable you have to declare your rpc classes)

connysvensson
4 Jun 2008, 3:26 AM
I finally got it to work. I had to change two things: Adding the IsSerializable (don't like that as it adds a dependency on gwt for my domain models). And changing all number classes to primitives, so changing Long to long, Integer to int, etc. The last one is really weird, I've seen a lot of examples which uses Long and Integer. Anyone had any similar problems with that? Maybe it's something in the Seam remoting implementation, as GWT supports number classes.

maku
4 Jun 2008, 4:28 AM
I finally got it to work. I had to change two things: Adding the IsSerializable (don't like that as it adds a dependency on gwt for my domain models). And changing all number classes to primitives, so changing Long to long, Integer to int, etc. The last one is really weird, I've seen a lot of examples which uses Long and Integer. Anyone had any similar problems with that? Maybe it's something in the Seam remoting implementation, as GWT supports number classes.

I've no problems with the Long, Integers and so on.

From my point of view it is (at least in my case) sometimes a problem with the *.rpc files (I work in noserver hosted mode with my own tomcat instance and I think this is sometimes the reason for troubles that the genereated rpc files could not be resolved) . You can check your rpc files. They should contain the serializable classes.
The directory of these generated files could be set by the -out flag when starting the GWTShell class. And the files should be resolvable.

Kutu
4 Jun 2008, 8:10 AM
In MyGWT 0.5 where there's only 1 model, I use Server-side reflection. I implemented a simple generic converter that can convert Model <-> Server-side object.

There are limitations in that reflection can't detect a generic list. To solve this problem, I added a helper class that store information regarding the converted class.

So the high-level pseudo-code looks like this


List<String> properties = new LinkedList<String();
// now add the properties you want to convert.

Helper helpModelA = new Helper();
helpModelA.setPropertyName(properties);

// Say the first property is of type List<SomeModel>
// setGenericType just put the property name and the type to a Map
helpModelA.setGenericType(properties.get(0), genericType);

Converter c = new Converter();

c.convert(serverSide, clientSide, helpModelA);


Inside the converter implementation, you use Reflection + list of properties + Helper

connysvensson
5 Jun 2008, 5:09 AM
I'm using the noserver option as well, runnig a JBoss server with Seam. It seems the number class problem went away after I upgraded to Seam 2.0.2SP1 (I used 2.0.2CR1 before). So the only thing I needed to change was to add IsSerializable, which seems to be a known problem with Seam remoting (hopefully will get fixed in the next version).

ttbgwt
27 Jun 2008, 7:14 AM
Do you have an example of your transformObject code that does this? Thanks!


I've been experimenting with some custom solutions to this problem. Like you, I didn't want redundant Client-side representations, and I wanted something that would easily be used by GXT's data models.

What I've come up with thus far is a 'ServerModel' class which has one static method "TransformObject" which takes two parameters:

Object o - the Object to Transform
String[] s - A list of strings representing the field names to grab from the object and stick in the DataModel. I've set it up to recurse through sub-objects as well, so an example would be:


BaseModelData m = ServerModel.transformObject(u, new String[] { "nameFirst", "nameLast", "email", "parent.email" } );
where U is a user User object with a field 'parent' which is also a User object (as well as a nameFirst etc... property)

This allows me to select only the fields I need for a given operation saving memory/transfer speeds. Obviously I should have a "transformObjects" method that would take a list returned from a Hibernate query.

So far this looks like something that will at least give me the short term efficiency gains I need while avoiding a lot of redundant code.

Thoughts?

si_gee2000
2 Jul 2008, 11:01 AM
Hi -

jumping in here, I have a framework for jboss to do this stuff. I'm sure it has plenty of inefficencies, but welcome to look.. It uses some shared "Primitives" and a combination of reflection on server side along with some annotations (like ignore this field etc). Handles nested stuff, references, lists etc, and supports saving the changes when they return. It does rely on a contract or to, and suffers from a couple of hacks for my own purposes. All in all tho its pretty general purpose.

You pass the RefDataCV objects around between client and server and bob's your uncle...

Example calls:

@EJB

StaticDataManager sdm;

@EJB
RefDataHelper rdm;

LOAD:

public RefDataCV getReferenceData(RefDataSupport entity) throws Exception {
RefDataCV rd= new RefDataCV();
if(entity != null) {

rdm.createRefData(obj, rd);
em.clear();

}
return rd;
}



SAVE:

try {
Object o;
boolean newInstance= false;
if(refdata.getEntityId() >= 0) {
//exists already

log.info("Lookup : " + refdata.getEntityId() + ":" + refdata.getEntityName());
o= sdm.find(refdata.getEntityId(), refdata.getEntityName());
log.info("FOUND object : " + o);
} else {
Class c= Thread.currentThread().getContextClassLoader().loadClass(refdata.getEntityName());
//construct a new object with no-args constructor

o= c.newInstance();
newInstance= true;
}
if(o instanceof RefDataSupport) {
RefDataSupport rds= (RefDataSupport)o;
rdm.storeRefData(refdata, rds);

if(newInstance) {
if(persist) em.persist(rds);
refdata.setEntityId(rds.getEntityId());
if(sessionId != null) eventCache.addEvent(ServerEvent.NEW_EVENT, rds.getEntityName(), rds.getEntityId(), sessionId, o);
} else {
if(sessionId != null) eventCache.addEvent(ServerEvent.UPDATE_EVENT, rds.getEntityName(), rds.getEntityId(), sessionId, o);
if(persist) em.merge(rds);
}
return rds;
} else {
if(o != null) {
thrownew RefDataSupportException(refdata.getEntityName());
} else {
thrownew Exception("Cannot find " + refdata.getEntityId() + ":" + refdata.getEntityName());
}
}

}
catch(PropertyValueException pve) {
log.log(Level.WARNING, pve.toString(), pve);
thrownew Exception("Property " + pve.getPropertyName() + " cannot be set to the given value, check data!");
}
catch(Exception e) {
log.log(Level.SEVERE, e.toString(), e);
throw e;
}



simon

si_gee2000
2 Jul 2008, 11:04 AM
Oh and have a look at the annotations available in RefField to control things that are "non-default"....

And an example RefDataSupport object:

package com.crs.proplan.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.validator.NotNull;
import com.crs.proplan.webapp.client.shared.DataGridEntry;
import com.crs.proplan.webapp.client.shared.IgnoreEntryException;

@Entity
@Table(name = "Currency", uniqueConstraints = {})
public class Currency implements java.io.Serializable, RefDataSupport {
// Fields
private int id;
private String name;
private String shortname;
private Integer ownerId;
// Constructors
/** default constructor */
public Currency() {
}
/** minimal constructor */
public Currency(int id) {
this.id = id;
}
// Property accessors
@Id @GeneratedValue
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false)
@NotNull
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "name", unique = false, nullable = true, insertable = true, updatable = true, length = 50)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "shortname", unique = false, nullable = true, insertable = true, updatable = true, length = 50)
public String getShortname() {
return this.shortname;
}
public void setShortname(String shortname) {
this.shortname = shortname;
}
@Column(name = "ownerId", unique = false, nullable = true, insertable = true, updatable = true)
public Integer getOwnerId() {
return this.ownerId;
}
public void setOwnerId(Integer ownerId) {
this.ownerId = ownerId;
}
// START RefDataSupport
@Transient
public Integer getEntityId() {
return getId();
}
@Transient
public String getEntityName() {
return getClass().getName();
}
@Transient
public String getDisplay() {
return getName();
}
//END RefDataSupport

}

zaccret
3 Jul 2008, 3:58 AM
I don't think you can transfer these objects to the client as there are still dependencies on Hibernate and javax (not translatable by GWT compiler).

si_gee2000
3 Jul 2008, 4:11 AM
The object above is not the object transferred - you have to use the attached framework in the zip file (RefDataHelper stuff) to turn it into a Serializable RefDataCV object, this is a simple object with a number of Primitive fields or nested RefDataCV objects that has no dependencies on the server side code. The RefDataHelper also manages merging or creating new objects when something is "uploaded" from the client.

The RefDataHelper just reflects on the object properties of the example shown here, and takes into account various RefFiled annotations you may have specified.

Hope that makes it clearer.. I have used this in a reasonably mature application for some time now with no probs!

cheers
simon

zaccret
3 Jul 2008, 4:17 AM
Sorry, I read your post too quickly :">. Thanks for explanations. By the way, you should also take a look at this new tutorial in the help center : http://extjs.com/helpcenter/topic/com.extjs.gxt.help/html/tutorials/dozer.html

si_gee2000
3 Jul 2008, 4:25 AM
Yes - I see Dozer is similar. I fear that as an early adopter of myGWT (pre GXT) I had to go thru that pain myself. The only thing that puts me off is the need to write mapping files - annotations aremore convenient. I looked at some other DTO fraemworks along these lines when I ventured into my own implementation - most do it that way, but I don;t want to map each field explicitly, I like the fact that (having rolled it myself) I can just push an object at the framework and it does the job, I only have to markup exceptions (like readonly fields and ignore fields) using the odd annotation.


nice stuff tho, maybe I'll hack that one about to my own ends too :)

si

drenda81
6 Jul 2008, 1:54 AM
Hi,
I've read your posts and I'm interesting in the use of hibernate4gwt with ext gwt. I've noticed that if my server rpc implementation extends HibernateRemoteService there is some problem when ext gwt makes rpc calls. Infact is thrown this exception:



GRAVE: Exception while dispatching incoming RPC call
net.sf.beanlib.BeanlibException: java.lang.NoSuchMethodException: com.extjs.gxt.ui.client.Style$SortDir$1.<init>()
at net.sf.beanlib.provider.replicator.BeanReplicator.replicateBean(BeanReplicator.java:103)
at net.sf.beanlib.hibernate3.Hibernate3JavaBeanReplicator.replicateBean(Hibernate3JavaBeanReplicator.java:71)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.replicateByBeanReplicatable(ReplicatorTemplate.java:115)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.replicate(ReplicatorTemplate.java:110)
at net.sf.beanlib.provider.BeanTransformer.transform(BeanTransformer.java:123)
at net.sf.beanlib.provider.BeanPopulator.doit(BeanPopulator.java:169)
at net.sf.beanlib.provider.BeanPopulator.processSetterMethod(BeanPopulator.java:133)
at net.sf.beanlib.provider.BeanPopulator.populate(BeanPopulator.java:104)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.populateBean(ReplicatorTemplate.java:164)
at net.sf.beanlib.provider.replicator.BeanReplicator.replicateBean(BeanReplicator.java:107)
at net.sf.beanlib.hibernate3.Hibernate3JavaBeanReplicator.replicateBean(Hibernate3JavaBeanReplicator.java:71)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.replicateByBeanReplicatable(ReplicatorTemplate.java:115)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.replicate(ReplicatorTemplate.java:110)
at net.sf.beanlib.provider.BeanTransformer.transform(BeanTransformer.java:123)
at net.sf.beanlib.provider.BeanPopulator.doit(BeanPopulator.java:169)
at net.sf.beanlib.provider.BeanPopulator.processSetterMethod(BeanPopulator.java:133)
at net.sf.beanlib.provider.BeanPopulator.populate(BeanPopulator.java:104)
at net.sf.hibernate4gwt.core.LazyKiller.populate(LazyKiller.java:253)
at net.sf.hibernate4gwt.core.LazyKiller.attach(LazyKiller.java:211)
at net.sf.hibernate4gwt.core.HibernateBeanManager.mergePojo(HibernateBeanManager.java:508)
at net.sf.hibernate4gwt.core.HibernateBeanManager.merge(HibernateBeanManager.java:282)
at net.sf.hibernate4gwt.gwt.HibernateRPCHelper.parseInputParameters(HibernateRPCHelper.java:80)
at net.sf.hibernate4gwt.gwt.HibernateRemoteService.processCall(HibernateRemoteService.java:164)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:85)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NoSuchMethodException: com.extjs.gxt.ui.client.Style$SortDir$1.<init>()
at java.lang.Class.getConstructor0(Class.java:2706)
at java.lang.Class.getDeclaredConstructor(Class.java:1985)
at net.sf.beanlib.provider.replicator.ReplicatorTemplate.newInstanceAsPrivileged(ReplicatorTemplate.java:202)
at net.sf.beanlib.hibernate3.Hibernate3JavaBeanReplicator.createToInstance(Hibernate3JavaBeanReplicator.java:66)
at net.sf.hibernate4gwt.core.beanlib.merge.MergeClassBeanReplicator.createToInstance(MergeClassBeanReplicator.java:215)
at net.sf.beanlib.provider.replicator.BeanReplicator.replicateBean(BeanReplicator.java:95)
... 40 more


If the server rpc implementation instead implements RemoteServiceServlet there is not this problem but I can't use this approach because hibernate4gwt requires that the RemoteService implements HibernateRemoteService.
So, there is some solution?

Thanks!

drenda81
6 Jul 2008, 11:08 AM
Hi,
I suggest to read this post http://extjs.com/forum/showthread.php?p=191249#post191249 that is linked to this one.

Thanks!

paulsschwarz
9 Aug 2008, 2:28 PM
Hi,

I am using GWT-SL-0.1.5, Hibernate3, hibernate4gwt-1.0.4_GWT_1.5RC1, GWT 1.5, GXT (or GWT EXT). I'm using hibernate4gwt in stateless mode and I'm using GWT-SL as Service Exporter. In an AOP manner I have written a class called MyHB4GWTRPCServiceExporter. This means I can intercept exceptions like invocation target exceptions before they go to GWT client as meaningless exceptions.

Ok, without GWT EXT I have NO problems. I can get complex collections of data from the database and transport them as pojos to my client, thanks to hibernate4gwt and GWT-SL. I like the power of pojos and hibernate4gwt, but with GXT I am able to set up bound widgets like data tables, combo boxes, etc very easily and elegantly if I stick to their Model idea. The Model is a map where you set your persistent fields as Key/Value pairs. This forms a naive sort of introspection. It works, but I like to be able to say user.getRoles() and not ((Roles) user.get("roles")). So how to get the best of both worlds? Well I thought I was being clever... and maybe was! I basically stuck to the Pojo idea that hibernate4gwt uses. But your pojos need to extend LazyGwtPojo if you're going to make hibernate4gwt happy, and need to extend BaseModel to make GXT happy. Can't have multiple inheritance. Truth is you don't NEED to extend LazyGwtPojo, you just need to implement ILazyPojo and its 4 methods. So I opened LazyGwtPojo and select all/copy/paste into a new class called MyLazyGwtPojo, which extends BaseModel (and implements ILazyPojo) so everyone's happy.

Now in my domain objects I realise that the properties are set using reflection via their setter methods. A pojo's setter looks like this:


public void setName(String name){
this.name = name;
}and a Model's setter looks like this:


public void setName(String name){
set("name", name);
}so my hybrid looks like this:


public void setName(String name){
set("name", name);
this.name = name;
}and again everyone is happy.

I tried it and it worked. To test I would do something like GWT.log(user.getName(), null); to check that the pojo side of things was working, and to test the Model side of things you need to use your object to put in a ListStore and then bind to a ComboBox, or something. It all worked.

Even transporting an object with a collection like a Set works.

But now the problem. In GXT you don't simply set up the normal AsyncCallback etc and invoke the service. You first set up data loading proxies and all sorts that kind of wrap up and abstract away some of the low details of paging/sorting requests, reloading, etc. Under the hood of course it's just normal GWT. Although sometimes I wonder because if I use GXT to retrieve something complex (a list of objects that have Sets of other objects - like teachers and their students) then suddenly the program has all the symptoms that hibernate4gwt has packed up and gone home. Sets are being sent to GWT as PersistentSets for instance which causes GWT to fail.

This gave me such headaches until I found this post http://extjs.com/forum/showthread.php?t=36428 where Maku seems like he's found the answer! I followed closely and he give away a bit more on page 2. Anyway finally piecing it all together I get this: in MyHB4GWTRPCServiceExporter I put the AOP advice method:


@Override
public String invokeMethodOnService(Object service, Method targetMethod, Object[]
targetParameters, RPCRequest rpcRequest) throws Exception {

Object result = targetMethod.invoke(service, targetParameters);

LazyKiller killer = new LazyKiller(null, HibernateUtil.getInstance()); //is this right?
if (result != null){
result = killer.detach(result);
}

String encodedResult = RPC.encodeResponseForSuccess(rpcRequest.getMethod(),
result, rpcRequest.getSerializationPolicy());

logger.debug(encodedResult);

return encodedResult;
}... and magically hibernate4gwt is back in the game! No more PersistentSets! They're all being converted back to safe HashSets.

Here it works (getting a "User" from the database with its associated "Authorities"):

//OK[0,9,21,10,13,20,6,13,19,6,13,18,-10,17,6,13,16,6,13,15,14,13,12,8,11,1,0,7,6,28,5,
6,10,6,6,1,9,0,0,1,0,7,-1,6,143,5,8,3,0,1,0,7,-1,6,144,5,4,3,2,2,1,["ke.co.mss.gsh.domain
.Users/2708089464","java.util.HashSet/1594477813","ke.co.mss.gsh.domain.Authorities/
396700231","ROLE_OFFICER","java.lang.Integer/3438268394","a","java.util.ArrayList/
3821976829","ROLE_ADMIN","java.lang.Boolean/476441737","xxx","com.extjs.gxt.ui.client
.data.RpcMap/3441186752","enabled","java.lang.String/2004016611","Yes","username",
"phone","userid","lastname","firstname","password","deleted"],0,3]

But now here's me trying to get an entire list of Users:

//OK[0,0,0,1,["com.extjs.gxt.ui.client.data.BasePagingLoadResult/496878394"],0,3]

BasePagingLoadResult is a wrapper that keeps a List of data and extra meta data like page offset and page limit (for paging). So you'd do myBasePagingLoadResult.getData() to get a List of Users. The list is full, if I put debug statements on the server I can see it has data. When I return it to the client I get //OK[0,0,0,1,["com.extjs.gxt.ui.client.data.BasePagingLoadResult/496878394"],0,3] so the object is not null, but myBasePagingLoadResult.getData() returns null!

If someone knows where my data has gone please let me know.

Thanks Paul

gslender
9 Aug 2008, 6:47 PM
Paul,

Maybe gxt Bean support will help? http://extjs.com/blog/2008/07/14/preview-java-bean-support-with-ext-gwt/

paulsschwarz
10 Aug 2008, 2:09 AM
Thanks gslender, what a legend! I've printed the article and gone through it, it's exactly what I need.

The article leads me onto another question:
Can someone please clear up for me what might just go down as one of the most confusing things I've ever come across!
What are:
MyGWT
GXT
Ext GWT
GWT-EXT

I notice the name Darrell Meyer comes up a lot in the product I am using. Does this mean I am a user of Ext GWT (NOT GWT-EXT)? And am I right is saying that Ext GWT was MyGWT but somehow merged with Ext JS?

So GWT EXT is EXT 2.0.2 (Javascript) wrapped up by GWT so it can be used in a GWT sort of way, whereas Ext GWT is a native implementation for GWT?

Also am I right in saying Ext GWT is officially up to version 1 but 1.1 is available under SVN? Can someone link me to instructions on how do check it out?

I found this article http://wiki.oreade.nl/Wiki.jsp?page=GwtExtSubversionDownloadCompile whos SVN URI is: http://gwt-ext.googlecode.com/svn
Am I right in saying that is NOT the one I want??

Sorry but I'm pretty confused and I really want to move ahead with the solution found at http://extjs.com/blog/2008/07/14/pre...-with-ext-gwt/ (http://extjs.com/forum/../blog/2008/07/14/preview-java-bean-support-with-ext-gwt/)

Thanks

gslender
10 Aug 2008, 3:40 AM
I notice the name Darrell Meyer comes up a lot in the product I am using. Does this mean I am a user of Ext GWT (NOT GWT-EXT)? And am I right is saying that Ext GWT was MyGWT but somehow merged with Ext JS?


Paul, I'd agree for someone new to all this, it would seem very confusing. /:)

ExtJS is an AJAX library that has both JavaScript/CSS and images/layout designs combined.

MyGWT was a GWT library that Darrell wrote that mimicked the concept and had similar looking widgets as ExtJS, but was totally GWT based and kinda was abandoned around early this year.

GWT-Ext is a "GWT based" wrapper around ExtJS, and requires an ExtJS license and associated JS/CSS libraries to work - there has been controversy over the legitimacy of the continued use of the older ExtJS library in light of a change to GPL. You'd also need to consider that you are really running a wrapper, which means GWT is calling a JS UI framework - and as you can imagine some things are a bit funky (IMO).

ExtGWT (or sometimes called GXT) is the name of a new ExtJS library totally based on GWT that will eventually offer all existing ExtJS widgets (plus others) including a full framework for building rich internet applications. Darrell joined the ExtJS team and re-wrote his MyGWT library which became v1.0 of ExtGWT.

You get ExtGWT SVN access with a support license. I'd suggest you read the product pages and post further questions to the forums as needed.

In saying that, I believe ExtJS are planning on release an alpha release of 1.1 very soon, so stick around and learn what you can.

Cheers,
Grant :D

paulsschwarz
10 Aug 2008, 4:23 AM
Hi Grant.
Awesome, thanks for the really good answer. So yes based on all that I am an ExtGWT (GXT) user. The other thing is due to the nature of my business (building small intranet apps on a one-off basis for clients) I believe I will need to but a developer license at $289.

I hope they do release 1.1 soooon because for the time being the bean support issue is a show stopper for me and GXT so when I'm running with that I'll be happy, at the moment I don't see why I need a full blown support license at $299!

I am more than happy to pay in for the dev license because that's what I am, but not so much the support licence just to get a 1.1 release a few days earlier than the official release date - bearing in mind it will probably take me a few days to figure out how to use SVN! ;)

So yeah, I just need to find out WHEN the 1.1 alpha will be out, then I'm sorted.

Enjoy the rest of your weekend, oh an congrats on Leizel Jones winning gold a few minutes ago.
Paul

ronaldmathies
19 Aug 2008, 9:14 AM
Hi all, just to keep this post up-to-date the website about compiling gwt-ext has changed:

http://java.sodeso.nl/web-frameworks/gwt-ext/how-to-get-the-very-latest-build-of-gwt-ext

paulsschwarz
30 Aug 2008, 2:17 PM
@ronaldmathies - now that I've finally got my head around the GWT-Ext vs. ExtGWT identity crisis how come you're linking us to a GWT-Ext page?

@gslender - hey Grant, I got the latest GXT 1.1 alpha 2 and I've got the bean support working (together with hibernate4gwt and GWT-SL) and the whole point of the exercise of using bean support was because I was getting PersistentSet problems. Then in this thread Maku suggested that with GWT-SL we need to AOP is a little a put something like this in:


@Override
public String invokeMethodOnService(Object service, Method targetMethod, Object[] targetParameters, RPCRequest rpcRequest) throws Exception {
Object result = targetMethod.invoke(service, targetParameters);
LazyKiller killer = new LazyKiller(null, HibernateUtil.getInstance());
if (result != null){
result = killer.detach(result);
}
String encodedResult = RPC.encodeResponseForSuccess(rpcRequest.getMethod(), result, rpcRequest.getSerializationPolicy());
return encodedResult;
}


which I did, and according to this thread remember I said that it successfully stopped the PersistentSet issues but my result set was empty. At that point you suggest the bean support from GXT 1.1. I THOUGHT that was going to solve all my issues in one hit. I set it up and still got PersistentSet issues, so I spent the day with a headache and finally thought of putting the AOP lazy killer code back in and disco.

Does that sound right to? i.e. do you expect to have to use the lazy killer even with bean support or am I doing something wrong? other than that it seems to be working (on a simple case at least).

Cheers
Paul

gslender
30 Aug 2008, 4:28 PM
Paul,

Can't say I fully understand your goal, but ultimately I would say that you are going to have stop any kind of lazy instantiation when using GWT as the client really can't pull the objects back via the server in that'case... think of the RPC call as being a teleporter whereby you must bring all your crap with you when you go - you can't be in two places at once. That concept is not the same when you are merely just wandering the streets of server-side-ville - in which cases you can happily leave your junk at home and drag into existance when you need it. Can't do that when you teleport over the GWT client side ;-)

In saying all that, I'm sure some smart cookie will figure out some cool way of doing that with GWT soon (or probably already has) but so far I'm not aware of that option.

paulsschwarz
30 Aug 2008, 11:01 PM
Ok that's a good answer and it's true, but when I think about it... before I introduced GXT to the mix I was using hibernate4gwt and gwtsl and I never got PersistentSet worries AND I didn't have to explicitly call the AOP-style lazy killing code. hibernate4gwt would look after all this automatically by the mere fact that my DTOs implemented ILazyPojo or extended LazyGwtPojo (now called LazyPojo in hibernate4gwt1.1).

It was only when I begun using GXT that these PersistentSet problems popped up, specifically because the DTOs were no longer pojos (I had a thing going where they implemented ILazyPojo and extended Model) which appeared to work but when you have collections you get the PersistentSet issue. Soooo that's when you recommended bean support which goes a long way to fix all this, but I still got the PersistentSet problem until I reintroduced the AOP lazy killer code.

My real question is, now that we have bean support why do we still need the lazy killer code?? (or have I done something wrong?)

Think about it this way, what data is moving between client and server? There's my User object which is a pojo extended LazyGwtPojo implementing BeanModelTag - so that should work just fine right? hibernate4gwt should look after itself there. But also the results I send back to the client are not just a list but a PagingLoadResult<User> (or a BasePagingLoadResult<User>) which neither implements ILazyPojo nor implements BeanModelTag. Could this have something to do with it? This is when I'm getting PersistentSet problems which are fixed by lazy killer code (which I can't help feeling shouldn't be necessary - nowhere in Bruno or George's set up instructions for hibernate4gwt and gwtsl does it tell you to do lazy killing explicitly)

Sorry for the dissertation!
Cheers
Paul ~o)

maku
31 Aug 2008, 10:20 PM
Ok that's a good answer and it's true, but when I think about it... before I introduced GXT to the mix I was using hibernate4gwt and gwtsl and I never got PersistentSet worries AND I didn't have to explicitly call the AOP-style lazy killing code. hibernate4gwt would look after all this automatically by the mere fact that my DTOs implemented ILazyPojo or extended LazyGwtPojo (now called LazyPojo in hibernate4gwt1.1).

It was only when I begun using GXT that these PersistentSet problems popped up, specifically because the DTOs were no longer pojos (I had a thing going where they implemented ILazyPojo and extended Model) which appeared to work but when you have collections you get the PersistentSet issue. Soooo that's when you recommended bean support which goes a long way to fix all this, but I still got the PersistentSet problem until I reintroduced the AOP lazy killer code.

My real question is, now that we have bean support why do we still need the lazy killer code?? (or have I done something wrong?)

Think about it this way, what data is moving between client and server? There's my User object which is a pojo extended LazyGwtPojo implementing BeanModelTag - so that should work just fine right? hibernate4gwt should look after itself there. But also the results I send back to the client are not just a list but a PagingLoadResult<User> (or a BasePagingLoadResult<User>) which neither implements ILazyPojo nor implements BeanModelTag. Could this have something to do with it? This is when I'm getting PersistentSet problems which are fixed by lazy killer code (which I can't help feeling shouldn't be necessary - nowhere in Bruno or George's set up instructions for hibernate4gwt and gwtsl does it tell you to do lazy killing explicitly)

Sorry for the dissertation!
Cheers
Paul ~o)

Paul,
I read not all your posts in detail. But maybe you mix two different things.

First: the hibernate stuff -> as you already mentioned -> you have to "detach" the hibernate specific stuff (e.g. with LazyKiller when you only want to detach or with more of the hibernate4gwt specific stuff when you want to handle a painless merging and so on when you transport your pojo's back to the server).
-> This is the prerequesite that you are able to transport your pojo's to gwt.

Second: the GXT stuff -> GXT needs some detail information of your pojo's. Because of in the GWT world we are not able to use reflection like in the "real" Java world. So we have to provide additional information. The easiest way to provide information in context of GXT 1.1 is to use BeanModel stuff and to code additional information in form of a marker interface:


@BEAN(CustomerEntity.class)
public interface CustomerBeanModel extends BeanModelMarker {

}
At least, when I unterstand it right the additional information can be generated when the GWT javascript stuff is generated.

paulsschwarz
31 Aug 2008, 10:38 PM
Thanks Maku,

So far my understanding is up to what you've explained, so at least I'm on the right track. You're right, I am using hibernate4gwt to look after painless use of hibernate DTOs across the server/client and then client/server line so that's fine. I am also marking my DTOs with BeanModelTag so that the compiler generates a second version of my DTO which is GXT ready.

This is all working fine and I have nothing to complain about except that I am required to explicitly invoke the LazyKiller of hibernate4gwt. That's not a problem because thanks to AOP I only do it once. What I am worried about is "am I really doing it right?" or is the requirement for me to call the LazyKiller a result of something I've set up wrong?

So my question is why am I finding the need to call LazyKiller when a) bean support allows pojos and b) hibernate4gwt should just automatically do the lazy killing by the mere fact that my DTO pojos are marked with ILazyPojo (or extend LazyGwtPojo)?

maku
1 Sep 2008, 5:47 AM
So my question is why am I finding the need to call LazyKiller when a) bean support allows pojos and b) hibernate4gwt should just automatically do the lazy killing by the mere fact that my DTO pojos are marked with ILazyPojo (or extend LazyGwtPojo)?

You don't have to call LazyKiller when you use hibernate4gwt as documented ( You can use LazyKiller explicitly when you ONLY need the detaching feature).
The details how to use it properly can be read in the hibernate4gwt docu.

paulsschwarz
1 Sep 2008, 6:00 AM
Thanks for that answer. I'm getting closer to understanding.

Sorry for being slow but what exactly is the detaching feature? or specifically what is detaching and what is a scenario of its use when using hibernate4gwt + GXT? I think the answer to that will tell me if my setup is right or wrong (either way my app IS working - but I want to get this right).

About the hibernate4gwt setup documentation... I've got printed copies of the documentation from various versions including the latest. I've read and re-read so I'm not sure what I'm doing wrong. I am using stateless mode. Also I'm using GWT-SL so the setup becomes a bit more complex.

I believe that I should not need to have the AOP advice that invokes the LazyKiller but still need to understand more before I know what to change to make it work without it.

Thanks :-?

maku
1 Sep 2008, 7:20 AM
Thanks for that answer. I'm getting closer to understanding.

Sorry for being slow but what exactly is the detaching feature? or specifically what is detaching and what is a scenario of its use when using hibernate4gwt + GXT? I think the answer to that will tell me if my setup is right or wrong (either way my app IS working - but I want to get this right).

About the hibernate4gwt setup documentation... I've got printed copies of the documentation from various versions including the latest. I've read and re-read so I'm not sure what I'm doing wrong. I am using stateless mode. Also I'm using GWT-SL so the setup becomes a bit more complex.

I believe that I should not need to have the AOP advice that invokes the LazyKiller but still need to understand more before I know what to change to make it work without it.

Thanks :-?

"Detaching" in this context means to replace the hibernate specific stuff (collections) and so on with "pure" java stuff (so that it is able to transfered to gwt)
I used it in an early state of an actual project because I didn't want dependencies to hibernate4gwt in the backend.
But in the meantime we moved and we are using hibernate4gwt in "stateless mode" because it is easier to handle. Now the entity classes extend LazyPojo.
We also use gwt-sl to export the services and so on.

Kango_V
1 Sep 2008, 2:37 PM
If you are using hibernate, you can use a projection query. This just involves having a DTO that you wish to return and Hibernate can fill it without creating your full hibernate object. This is very fast, and removes a lot of cruft.

This is an example of filling a single object (ComponentRequirement) from 4 tables from Mapics in our AS/400. This saves creating the object graph and then having to traverse it to fill an object. Hibernate does it for you :)



@SuppressWarnings("unchecked")
public List<ComponentRequirement> getRequirement(Criterion ... criterion)
{
Criteria criteria = prepareObjectCriteria(OrderReview.class);
criteria.createAlias(OrderReview.Attributes.ITEM_BALANCE, "bl", Criteria.INNER_JOIN);
criteria.createAlias(OrderReview.Attributes.ITEM_MASTER_A_RECORD, "itema", Criteria.INNER_JOIN);
criteria.createAlias(OrderReview.Attributes.ITEM_MASTER_B_RECORD, "itemb", Criteria.LEFT_JOIN);
criteria.createAlias(OrderReview.Attributes.VENDOR_ITEM_EXTENDED_DESCRIPTION, "viext", Criteria.LEFT_JOIN);
criteria.setProjection( Projections.projectionList()
.add( Projections.property("itemNumber"), ComponentRequirement.Attributes.ITEM_NUMBER )
.add( Projections.property("vendorNumber"), ComponentRequirement.Attributes.VENDOR_NUMBER )
.add( Projections.property("planningWarehouse"), ComponentRequirement.Attributes.WAREHOUSE )
.add( Projections.property("orderDueDateISO"), ComponentRequirement.Attributes.ORDER_DUE_DATE_ISO )
.add( Projections.property("orderNumber"), ComponentRequirement.Attributes.ORDER_NUMBER )
.add( Projections.property("newQuantity"), ComponentRequirement.Attributes.NEW_QUANTITY )
.add( Projections.property("itema.itemDescription"), ComponentRequirement.Attributes.ITEM_DESCRIPTION )
.add( Projections.property("itemb.currentCosts.thisLevel.material"), ComponentRequirement.Attributes.CURRENT_MATERIAL_THIS_LEVEL )
.add( Projections.property("viext.extendedQuoteDescription1"), ComponentRequirement.Attributes.EXTENDED_QUOTE_DESCRIPTION_1 )
.add( Projections.property("bl.itemClass"), ComponentRequirement.Attributes.ITEM_CLASS )
.add( Projections.property("bl.planner"), ComponentRequirement.Attributes.PLANNER )
.add( Projections.property("bl.warehouseStockLocation"), ComponentRequirement.Attributes.WAREHOUSE_STOCK_LOCATION ) );
criteria.setResultTransformer( new AliasToBeanResultTransformer(ComponentRequirement.class) );
if (criterion != null && criterion.length > 0)
{
for (Criterion criterion2 : criterion)
{
criteria.add(criterion2);
}
}
return criteria.list();
}



Forgot to mention, this will fire a single SQL statement to retrieve the data. Have fun.