Announcement Announcement Module
Collapse
No announcement yet.
Spring AOP, Transaction and Hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    Help

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

    Comment


    • #3
      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

      Comment


      • #4
        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 ) {}

        Comment


        • #5
          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

          Comment


          • #6
            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.

            Comment


            • #7
              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

              Comment


              • #8
                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>

                Comment


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

                  Fred

                  Comment


                  • #10
                    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.

                    Comment

                    Working...
                    X