Expand my Community achievements bar.

Java to Actionscript conversion problem

Avatar

Former Community Member
Hi all,



I have got a strange problem with java to actionscript
conversion that i have not been able to figure out.



Ive got an actionscript VO mapped to a java VO, and when i
call my remote object from actionscript that returns a collection
of VO, surprisingly some of my objects in the collection are Object
type an others are VO type. The rarest thing is that the omount of
Object types vary when refreshing the application.



If I debug my Java DAO, it is returning a Collection full of
VO instances, but when debugging actionscript, some of them are
Object instance.



Any clues?



Lee Oneal.
7 Replies

Avatar

Level 3
Are you using RemoteObject or DataService?



Do you have only one type of VO?



Out of curiosity, does the VO implement any of the java
standard interfaces such as java.io.Externalizable,
java.util.Collection, java.util.List or java.util.Map?

Avatar

Former Community Member
I am using Remote Object, my Java VO implements
java.io.Serializable. I am also using hibernate 3.



Here is my code.



Actionscript VO

===========

package com.imagemaker.olimpo.contacto.vo {



import com.adobe.cairngorm.vo.ValueObject;

import mx.collections.ArrayCollection;



[Bindable]

[RemoteClass(alias="com.imagemaker.olimpo.beans.Empresa")]



public class EmpresaVO implements ValueObject {

public var id:int;

public var nombre:String;

public var direccion:String;

public var rut:String;

public var contactos:ArrayCollection;

}

}



Java VO

=======

package com.imagemaker.olimpo.beans;



/**

* AbstractEmpresa generated by MyEclipse - Hibernate Tools

*/



public abstract class AbstractEmpresa implements
java.io.Serializable {



private Integer id;

private String nombre;

private String direccion;

private String rut;



// Constructors



/** default constructor */

public AbstractEmpresa() {

}



/** minimal constructor */

public AbstractEmpresa(String nombre) {

this.nombre = nombre;

}



/** full constructor */

public AbstractEmpresa(String nombre, String direccion,
String rut) {

this.nombre = nombre;

this.direccion = direccion;

this.rut = rut;

}





// Property accessors



public Integer getId() {

return this.id;

}



public void setId(Integer id) {

this.id = id;

}



public String getNombre() {

return this.nombre;

}



public void setNombre(String nombre) {

this.nombre = nombre;

}



public String getDireccion() {

return this.direccion;

}



public void setDireccion(String direccion) {

this.direccion = direccion;

}



public String getRut() {

return this.rut;

}



public void setRut(String rut) {

this.rut = rut;

}

}





package com.imagemaker.olimpo.beans;

// Generated by MyEclipse - Hibernate Tools



import java.util.Set;





/**

* Empresa generated by MyEclipse - Hibernate Tools

*/

public class Empresa extends AbstractEmpresa implements
java.io.Serializable {



// Constructors



/**

*

*/

private static final long serialVersionUID =
-5039282446108510122L;



/** default constructor */

public Empresa() {

}



/** minimal constructor */

public Empresa(String nombre) {

super(nombre);

}



/** full constructor */

public Empresa(String nombre, String direccion, String rut)
{

super(nombre, direccion, rut);

}



}





My service returns a List of Empresa and in Actionscript not
all of my objects in the collection are transformed into EmpresaVO



Please HELP!!!



Thanks,



Lee Oneal

Avatar

Level 3
Hi Lee,



I don't immediately see anything wrong here. I can only start
guessing at various theoretical situations.



1. Can you experiment with delaying your RemoteObject call
until after the creationComplete event has fired from the top level
<mx:Application>?



2. I see your AS VO has a contactos:ArrayCollection
property... but this doesn't seem to correlate to anything in your
Java VO... did you forget some code in your last message as I see
you import java.util.Set in Empresa but never use it?



3. When you say your RemoteObject returns a "collection of
VO"... what is the Java type explicitly of this collection? Is
there some getEmpresas() method? If so, can I see that method
signature?



4. Do you send the exact same instance of any of the Empresa
objects back in the collection more than once? AMF allows for
serialization by reference... perhaps the items that are being
returned as anonymous Object instead of VO instances are related to
this and may help us track down the cause?



5. This should not matter, but we need to think outside of
the box to track this issue down... can you try changing things
about your VO to isolate the cause... try removing certain
interfaces like Serializable and try again.



Pete

Avatar

Former Community Member
Hi Pete,



thanks for te help.



1. Can you experiment with delaying your RemoteObject call
until after the creationComplete event has fired from the top level
<mx:Application>?

<strong>Ans: done</strong>



2. I see your AS VO has a contactos:ArrayCollection
property... but this doesn't seem to correlate to anything in your
Java VO... did you forget some code in your last message as I see
you import java.util.Set in Empresa but never use it?

<strong>Ans: done</strong>



3. When you say your RemoteObject returns a "collection of
VO"... what is the Java type explicitly of this collection? Is
there some getEmpresas() method? If so, can I see that method
signature?

<strong>

SERVICE

=======

</strong>



public List getEmpresas() {

EmpresaDAOImpl impl = (EmpresaDAOImpl)
FactoryDao.getInstance().getDao(EmpresaDAO.class);



return impl.getAll(Empresa.class);

}



<strong>

HIBERNATE PORTION

==================

</strong>

public List getAll(Class clase) {

try {

Session session = HibernateUtil.currentSession();

Query query = session.createQuery("from " +
clase.getSimpleName());

List lista = query.list();

return lista;

} catch (HibernateException e) {

HibernateUtil.closeSession();

throw e;

}

}





4. Do you send the exact same instance of any of the Empresa
objects back in the collection more than once? AMF allows for
serialization by reference... perhaps the items that are being
returned as anonymous Object instead of VO instances are related to
this and may help us track down the cause?

<strong>Ans: NO,
[com.imagemaker.olimpo.beans.Empresa@15e7597,
com.imagemaker.olimpo.beans.Empresa@16cdbb8,
com.imagemaker.olimpo.beans.Empresa@1cd2b82]</strong>



5. This should not matter, but we need to think outside of
the box to track this issue down... can you try changing things
about your VO to isolate the cause... try removing certain
interfaces like Serializable and try again.

<strong>Ans:done</strong>



I´ve done all your recomendatios and the problem
continues. I´ve maid some debuggin in flex builder an I found
something strange:



<ul>

<li>this =
com.imagemaker.olimpo.contacto.command.GetEmpresasCommand
(@4e25ee1)</li>

<li>data = mx.rpc.events.ResultEvent
(@929b079)</li>

<li>

event = mx.rpc.events.ResultEvent (@929b079)

<ul>

<li>bubbles = false</li>

<li>cancelable = true</li>

<li>currentTarget = null</li>

<li>eventPhase = 2 [0x2]</li>

<li>message = mx.messaging.messages.AcknowledgeMessage
(@8e3c121)</li>

<li>messageId =
"742853CB-9E08-B9B2-3637-07521BD5E837"</li>

<li>

result = mx.collections.ArrayCollection (@9334701)

<ul>

<li>

[0] = Object (@931b2c1)

<ul>

<li>callbacks = Array (@9334071)

<ul>

<li>

[0] = Object (@931b221)

<ul>

<li>identifier = 1 [0x1]</li>

<li>implementation =
com.imagemaker.olimpo.contacto.vo.EmpresaVO (@92d5449)

<ul>

<li>direccion = "Hernando de Aguirre 268 of.
502"</li>

<li>id = 1 [0x1]</li>

<li>nombre = "Imagemaker IT"</li>

<li>rut = null</li>

</ul>

</li>

<li>session = Object (@92e6b41)</li>

</ul>

</li>

<li>length = 1 [0x1]</li>

</ul>

<li>direccion = "Hernando de Aguirre 268 of.
502"</li>

<li>id = 1 [0x1]</li>

<li>nombre = "Imagemaker IT"</li>

<li>rut = null</li>

</ul>

</li>

<li>[1] = Object (@92e6201)</li>

<li>[2] = com.imagemaker.olimpo.contacto.vo.EmpresaVO
(@92d58a9)</li>

<li>filterFunction = null</li>

<li>length = 3 [0x3]</li>

<li>list = mx.collections.ArrayList
(@8f6c201)</li>

<li>sort = null</li>

<li>source = Array (@9334761)</li>

</ul>

</li>

<li>target = null</li>

<li>token = mx.rpc.AsyncToken (@92e21a1)</li>

<li>type = "result"</li>

</ul>

</li>

</ul>

You can notice that not all of my instances are transformed
to EmpresaVO, but inside callbacks they are.



Why is that?



May be this could help to figure this out.



thanks,



Lee

Avatar

Level 3
Hi Lee,



What does the contactos property of an EmpressaVO contain?
Other EmpressaVOs?



Seth

Avatar

Level 3
So it turns out the problem was due to Lee's use of Hibernate
from within his remote object implementation. Hibernate optionally
uses CGLib to generate proxy classes to wrap your domain classes,
and this is how it does lazy loading and keeps track of dirty
fields and changes in the relationships between associated object
instances. The problem is that the proxies generated by Hibernate
cannot be registered on the client using [RemoteClass..] metadata.



Here's a snippet from Lee's log:

[0] = (Typed Object #4
'com.imagemaker.olimpo.beans.Empresa$$EnhancerByCGLIB$$df39c9ea')



The class name gen'ed by Hibernate is:
Empresa$$EnhancerByCGLIB$$df39c9ea



So when it reaches the client it is deserialized as an
anonymous Object because there's no registered AS class that
correlates.



Here's more detail along with suggestions to resolve this
courtesy of Jeff:





We ran into this problem with the HibernateAssembler used by
the Data Management Services. The issue is that by default,
hibernate creates a sub-class of your VO which it generates using
CGLIB. This class overrides any “getX” method for an
association property to first fetch that value before returning it.
This is hibernate’s “lazy loading” feature.



The class name of the VO is being sent over and so this is
likely not matching your RemoteClass alias on the client side. This
thing also has other properties like the implementation and
probably some stuff which is not serializable.



I think that there is a way to turn of the use of CGLIB
proxies in hibernate though I don’t know the exact
configuration. This would be one way to workaround the problem. In
the hibernate assembler, we register a class called the
HiberatePropertyProxy for any objects encountered in the AMF stream
which implement the HibernateProxy interface. In this case, the
proxy object is used to unwrap and send the original instance
instead of sending the proxy. You can also just unwrap the proxy
before sending it to us with:



return
((HibernateProxy)instance).getHibernateLazyInitializer().getImplementation();



One issue is that for any association properties you have
(i.e. references to other objects), you’ll need to make sure
those instances have been fetched before your transaction is
closed.



The code for the hibernate assembler is included in the
product in:



.../fds2/resources/samples/assemblers/flex-messaging-dist-src.zip




Another option is to just use the hibernate assembler instead
of using remote object and we’ll take care of this for you.



Jeff