Results 1 to 10 of 10

Thread: Spring AOP, Transaction and Hibernate

  1. #1
    Join Date
    Sep 2007
    Posts
    7

    Default Spring AOP, Transaction and Hibernate

    Hello, I have a problem when I enable AOP transactions on services that are using hibernate based DAO.

    Here is my domain model and hibernate mapping file:

    Code:
    public abstract class PaymentMethod
            implements Serializable
    {
        public Integer getId()
        {
            return _id;
        }
    
        public void setId( final Integer id )
        {
            _id = id;
        }
    
        public String getName()
        {
            return _name;
        }
    
        public void setName( final String name )
        {
            _name = name;
        }
    
        public Subscriber getSubscriber()
        {
            return _subscriber;
        }
    
        public void setSubscriber( final Subscriber subscriber )
        {
            _subscriber = subscriber;
        }
    
        private Integer _id;
        private String _name;
        private Subscriber _subscriber;
    }
    Code:
    public class InternalCard
            extends PaymentMethod
    {
        public Double getBalance()
        {
            return _balance;
        }
    
        public void setBalance( final Double balance )
        {
            _balance = balance;
        }
    
        private Double _balance;
    }
    Code:
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping default-cascade="save-update" auto-import="false">
    
        <class name="com.f4.owl.domain.billing.PaymentMethod" table="bil_payment_method" schema="public">
    
            <id name="id" type="java.lang.Integer">
                <column name="bil_payment_method_id"/>
                <generator class="sequence">
                    <param name="sequence">bil_payment_method_bil_payment_method_id_seq</param>
                </generator>
            </id>
    
            <property name="name" type="string">
                <column name="bil_payment_method_name" length="50" not-null="true"/>
            </property>
    
            <many-to-one name="subscriber" class="com.f4.owl.domain.billing.Subscriber" fetch="select">
                <column name="acc_account_id" not-null="true"/>
            </many-to-one>
    
            <joined-subclass name="com.f4.owl.domain.billing.InternalCard" table="bil_internal_card">
                <key column="bil_payment_method_id"/>
    
                <property name="balance" type="java.lang.Double">
                    <column name="bil_internal_card_balance" precision="8" scale="0" not-null="true"/>
                </property>
    
            </joined-subclass>
    
        </class>
        
    </hibernate-mapping>
    As you can see, the payment method class is abstract, Internal Card, Credit Card and so on are concrete classes.

    Here is my AOP configuration:

    Code:
        <!-- the aspects -->
        <tx:advice id="billingTransactionAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="buy*"/>
                <tx:method name="change*"/>
                <tx:method name="create*"/>
                <tx:method name="delete*"/>
                <tx:method name="get*" read-only="true"/>
                <tx:method name="pay*"/>
                <tx:method name="transfer*"/>
                <tx:method name="use*"/>
                <tx:method name="refresh*" read-only="true"/>
                <tx:method name="revive*" read-only="true"/>
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <aop:pointcut id="billingOperation" expression="execution(* com.f4.owl.service.billing.BillingService.*(..))"/>
            <aop:advisor advice-ref="billingTransactionAdvice" pointcut-ref="billingOperation"/>
            <aop:aspect id="detailsLog" ref="detailsLogAspect">
                <aop:around pointcut-ref="billingOperation" method="log"/>
            </aop:aspect>
            <aop:aspect id="performanceLog" ref="performanceLogAspect">
                <aop:around pointcut-ref="billingOperation" method="log"/>
            </aop:aspect>
        </aop:config>
    The following piece of code is used in a transactional method of the billing service :

    Code:
    ...
    PaymentMethod paymentMethod = _paymentMethodDAO.selectByPrimaryKey( paymentMethodId );
    
    Assert.assertTrue( paymentMethod instanceof PaymentMethod);
    Assert.assertTrue( paymentMethod instanceof InternalCard );
    ...
    Here is the simplified code in the DAO for the selectByPrimaryKey():

    Code:
        ...
        return (PaymentMethod) session.get(PaymentMethod.class, primaryKey);
        ...
    When I use no transactions, the 2 asserts succeed.
    When I enable transactions, the second assert failed.

    Why is the payment method is proxied in transaction ?
    Why the InternalCard is proxied as a PaymentMethod ?

    Thanks

  2. #2
    Join Date
    Sep 2007
    Posts
    7

    Default Help

    Nobody to help me ;-((((( ???

  3. #3
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    You use JDK dynamic proxies which work on interfaces. There are also CGLib proxies working on classes, but why do you want to do so?

    Joerg
    This post can contain insufficient information.

  4. #4
    Join Date
    Sep 2007
    Posts
    7

    Default

    Thank you for your answer.

    Yes, I know JDK proxies works on interface. But I have no interfaces here just the abstract classes PaymentMethod and the concrete class InternalCard. So I don't understand why the type of the proxy is PaymentMethod and not InternalCard.

    " ... but why do you want to do so?"

    I have associated a PaymentPlatform bean to the PaymentMethod class in my service class. So when a user want to pay something i use the payment method class to retrieves the good payment platform bean ...

    PaymentPlatform getPaymentPlatform( Class<? extends PaymentMethod> paymentMethodClass ) {}

  5. #5
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote Originally Posted by fnowal View Post
    But I have no interfaces here just the abstract classes PaymentMethod and the concrete class InternalCard. So I don't understand why the type of the proxy is PaymentMethod and not InternalCard.
    Ah, ok, my shoot was too fast. You are working with Hibernate here, aren't you? This uses CGLib only anyway. CGLib creates proxies by subclassing the actual object. My guess is now that you search for PaymentMethod, you get all your instances as PaymentMethods, but not as their actual implementations. But I don't know for sure how Hibernate behaves here.

    Joerg
    This post can contain insufficient information.

  6. #6
    Join Date
    Sep 2007
    Posts
    7

    Default

    Thank you for your answer again.

    When I disable AOP transactions, everything works fine, the object retrieved from the DAO is of the good type (InternalCard). The problem is not coming from Hibernate on my opinion.

    When I activate AOP transactions, on the Service Layer, the object type becomes PaymentMethod. The problem appears even with cglib proxies.

    I think there is a problem out there. Why, the DAO behaves differently when I activate transactions on the service layer ? Isn't there a conflict between Spring AOP and Hiberate CGLib use ? I will dig the sources and bring more informations when I'll have time.

  7. #7
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote Originally Posted by fnowal View Post
    Why, the DAO behaves differently when I activate transactions on the service layer ?
    They should indeed not interfere each other at all. What exactly do you do when you disable or enable transactions?

    Joerg
    This post can contain insufficient information.

  8. #8
    Join Date
    Sep 2007
    Posts
    7

    Default

    I comment the advisor in the aop:config

    Code:
    <aop:config>
            <aop:pointcut id="billingOperation" expression="execution(* com.f4.owl.service.billing.BillingService.*(..))"/>
            <!--aop:advisor advice-ref="billingTransactionAdvice" pointcut-ref="billingOperation"/-->
            <aop:aspect id="detailsLog" ref="detailsLogAspect">
                <aop:around pointcut-ref="billingOperation" method="log"/>
            </aop:aspect>
            <aop:aspect id="performanceLog" ref="performanceLogAspect">
                <aop:around pointcut-ref="billingOperation" method="log"/>
            </aop:aspect>
        </aop:config>

  9. #9
    Join Date
    Sep 2007
    Posts
    7

    Default

    I will prepare a sample archive to investigate this problem, I will post it as soon as possible.
    Thanks for your answers Joerg.

    Fred

  10. #10
    Join Date
    Sep 2007
    Posts
    7

    Default

    I think my problems come from hibernate not Spring AOP ...
    It may be a hazard that the behaviour changes when I activate AOP.
    I wil post a reply when I will have the solution.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •