Announcement Announcement Module
Collapse
No announcement yet.
Flex+Hibernate registered HibernateProxy converter is never called Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Flex+Hibernate registered HibernateProxy converter is never called

    Hi,

    I'm integrating a spring-flex app with Hibernate.

    I've followed the tutorial in

    http://static.springsource.org/sprin...e-introduction

    to prevent the n+1 select on entities sets from happening.

    The docs state that the HibernateProxyConverter should be automatically registered but, just in case, I manually registered it to be able to debug the calls.

    Here's the problem:

    The converter's getConvertibleTypes method is called at startup, proofing that the converter is been registered, but the convert method for HibernateProxy is never called, resulting in the "no session or session was closed" exception for lazy collections.

    I tried registering my own converter for PersistentBag/PersistentSet and, for eager collections, the convert method is called (no much use, is it?). Still, for lazy collections, the convert method is never invoked.

    From my understanding, HibernateProxy should automatically wrap persistent collections and the converter should catch the getter's invokation during serialisation and return the appropriate value depending on whether the proxy is initialised or not.

    That is not happening.

    Here's my entity (the getRoles() getter is the one showing the problem here)

    Code:
    package it.aekidna.wottudu.model.vo;
    
    import java.util.Set;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.Table;
    import javax.persistence.Transient;
    
    import org.springframework.flex.core.io.AmfIgnore;
    
    @Entity
    @Table(name="`PERSON`")
    public class UserEntity {
        
        private String firstName;
        private Integer id;
    
        private String lastName;
    
        private String password;
    
        private Set<SecurityRoleEntity> roles;
    
        private String username;
    
        /**
         * @return the firstName
         */
        public String getFirstName() {
            return firstName;
        }
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id")
        public Integer getId() {
            // TODO Auto-generated method stub
            return Integer.valueOf(0);
        }
    
        /**
         * @return the lastName
         */
        public String getLastName() {
            return lastName;
        }
        @AmfIgnore
        public String getPassword() {
            // TODO Auto-generated method stub
            return password;
        }
        @ManyToMany(cascade = CascadeType.ALL, 
                fetch=FetchType.LAZY )
        @JoinTable(
            name = "`PERSON_PERSONROLE_MTM`",
            joinColumns = { 
                    @JoinColumn(name = "personid") }, 
            inverseJoinColumns = { 
                    @JoinColumn(name = "personroleid") })
        public Set<SecurityRoleEntity> getRoles() {
            return roles;
        }
        
        /**
         * @return the username
         */
        public String getUsername() {
            return username;
        }
        
        
        @Transient
        public boolean isActive() {
            // TODO Auto-generated method stub
            return true;
        }
        
        /**
         * @param firstName the firstName to set
         */
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
    
        /**
         * @param id the id to set
         */
        public void setId(Integer id) {
            this.id = id;
        }
    
        /**
         * @param lastName the lastName to set
         */
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        /**
         * @param password the password to set
         */
        public void setPassword(String password) {
            this.password = password;
        }
    
        /**
         * @param roles the roles to set
         */
        public void setRoles(Set<SecurityRoleEntity> roles) {
            this.roles = roles;
        }
    
        /**
         * @param username the username to set
         */
        public void setUsername(String username) {
            this.username = username;
        }
    
    }
    here's my flex config snippet

    Code:
        <bean 
             id="amfConfigProcessor" 
             class="it.aekidna.wottudu.spring.CustomProcessor">
             <constructor-arg><value>it.aekidna.wottudu.model.vo</value></constructor-arg>
             <property name="useDirectFieldAccess" value="false" />
         </bean>
        <flex:message-broker >
            <flex:config-processor ref="amfConfigProcessor" />
            <flex:message-service
                default-channels="my-streaming-amf,my-longpolling-amf,my-polling-amf" />
            <flex:secured per-client-authentication="true" />
        </flex:message-broker>
    Here's the CustomProcessor:

    Code:
    package it.aekidna.wottudu.spring;
    
    import org.springframework.core.convert.converter.ConverterRegistry;
    import org.springframework.flex.core.io.ClassPathScanningAmfConversionServiceConfigProcessor;
    import org.springframework.flex.core.io.PersistentCollectionConverterFactory;
    
    public class CustomProcessor extends
            ClassPathScanningAmfConversionServiceConfigProcessor {
    
        public CustomProcessor(String basePackage) {
            super(basePackage);
        }
        
         @Override
         protected void configureConverters(ConverterRegistry registry) {
             registry.addConverter(new CustomConverter());
             registry.addConverterFactory(new PersistentCollectionConverterFactory());
         }
        
    }
    and here's the converter

    Code:
    package it.aekidna.wottudu.spring;
    
    import java.util.Collections;
    import java.util.Set;
    
    import org.hibernate.Hibernate;
    import org.hibernate.proxy.HibernateProxy;
    import org.springframework.core.convert.TypeDescriptor;
    import org.springframework.flex.core.io.HibernateProxyConverter;
    
    public class CustomConverter extends HibernateProxyConverter {
    
            //THIS IS NEVER CALLED
        @Override
        public Object convert(Object inSource, TypeDescriptor inSourceType, TypeDescriptor inTargetType) {
            if( inSource != null)
            {
                if( inSource instanceof HibernateProxy )
                {
                    if( Hibernate.isInitialized( inSource ) )
                    {
                        return inSource;
                    }
                    else
                    {
                        return null;
                    }
                
                }
            }
            return inSource;
        }
    
        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            // TODO Auto-generated method stub
            return Collections.singleton(new ConvertiblePair(HibernateProxy.class, Object.class));
    
        }
    
    }
    Any clue?

    Thanks!

    Using
    Spring-flex 1.5.2
    Hibernate 3.6.10
    Spring 3.0.0
    BlazeDS 4.0.0
    Tomcat 7
    Last edited by aekidna; Dec 10th, 2012, 08:45 AM.

  • #2
    Update.

    the conversion seems to be failing when the below method of GenericConversionService is called:
    Code:
    	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
    		assertNotNull(sourceType, targetType);
    		if (sourceType == TypeDescriptor.NULL) {
    			Assert.isTrue(source == null, "The source must be null if sourceType == TypeDescriptor.NULL");
    			return convertNullSource(sourceType, targetType);
    		}
    		if (targetType == TypeDescriptor.NULL) {
    			return null;
    		}
    		GenericConverter converter = getConverter(sourceType, targetType);
    		if (converter == null) {
    			throw new ConverterNotFoundException(sourceType, targetType);
    		}
    		return ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
    	}
    for PersistentSet this line returns true

    Code:
    sourceType == TypeDescriptor.NULL
    Inspecting sourceType I noticed that the value property is null.

    therefore, what happens is that the following line causes the exception to be thrown (I guess it causes the lazy PersistentBag to be loaded)

    Code:
    Assert.isTrue(source == null, "The source must be null if sourceType == TypeDescriptor.NULL");

    Comment

    Working...
    X