Accueil > Equinox Aspects, JPA, JPA/EclipseLink, OSGi, Spring DM, Spring ORM, Springweaver > Load-Time Weaving for Spring-DM with JPA/EclipseLink [step1]

Load-Time Weaving for Spring-DM with JPA/EclipseLink [step1]


Martin Lippert has created org.eclipse.equinox.weaving.springweaver (version 0.1.1) bundle to manage Spring LoadTimeWeaver into OSGi context (Equinox only) which is based on Equinox Aspects.

I have tried to use org.eclipse.equinox.weaving.springweaver (version 0.1.1) into JPA context with EclipseLink, but weaving doesn’t work very well ( see SpringWeaver (0.1.1) -JPA problem for more information). I think (but not sure) that Martin Lippert has tested org.eclipse.equinox.weaving.springweaver only with Spring @Configurable.

So I decided to create a new version of org.eclipse.equinox.weaving.springweaver (version 0.1.2) to manage LoadTimeWeaver into JPA context, that you can find on Dynaresume SVN – SpringWeaver.

SpringWeaver (0.1.1) -JPA problem

EclipseLink weaving

EclipseLink is ORM which manage several features like « lazy-loading« . Here a basic sample of JPA lazy-loading done for the login property with @Basic(fetch=FetchType.LAZY) JPA annotation :

@Entity
@Table(name = "T_USER")
public class User {

...
	@Column(name = "USR_LOGIN_C")
	@Basic(fetch=FetchType.LAZY)
	private String login;

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}
...
}

If User#getLogin() is called, SQL Select Query will be executed to get the value of the property into Database (only if login property has been not already loaded).

To manage « lazy-loading », EclipseLink transform the bytecode of the Domain class which must be persisted to add listener into getter/setter and call EclipseLink code (open connection…). (I think it’s more elegant solution than Hibernate which use CGLIB/Javasssit Proxy, and it works better into OSGi context). Bytecode transformation is done with Java Agent into NOT OSGi context and with Equinox Hook into OSGi context. So with EclipseLink, every Domain bundle classes must be transformed (« woven »).

To check if EclipseLink weaving is done, you can test if the instance of domain class implements the EclipseLink interface org.eclipse.persistence.internal.weaving.PersistenceWeaved :

User  user = ...
if (user instanceof PersistenceWeaved) {
  // Weaving was done
} 

SpringWeaver (0.1.1) -JPA problem

The problem with org.eclipse.equinox.weaving.springweaver (version 0.1.1) into OSGi context is that the weaving classes is done ONLY for classes belong to the bundle which declare the LoadTimeWeaver bean :

<bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver"/>

Into JPA context, you have :

  • one or several « Domain Bundle » which contains domain (model) classes.
  • a « JPA Bundle » which contains :
    • JPA persistence.xml
    • declare JPA entityManagerFactory bean
    • declare org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver bean (which is used by entityManagerFactory bean).

    Into JPA context it’s « Domain Bundle » which must be woven, but EquinoxAspectsLoadTimeWeaver is declared into JPA Bundle (only classes from JPA Bundle can be woven).

    If you use SpringWeaver (0.1.1) with EclipseLink, EquinoxAspectsLoadTimeWeaver allow you to avoid having Spring LoadTimeWeaver error :

    Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
    at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:78)

    But domain classes weaving is not done! It’s the same result than when you deactivate weaving EclipseLink with eclipselink.weaving property :

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    ...		
    	<property name="jpaProperties">
    		<bean id="jpaProperties"
    			class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    			<property name="properties">
    				<props>
    					<prop key="eclipselink.weaving">true</prop>
    				</props>
    			</property>
    		</bean>
    	</property> 
    ...

    SpringWeaver (0.1.2) -JPA solution

    The solution is that the weaving must be done for the whole classes of each bundles. I have managed that into the SpringWeaver (0.1.2) by adding weaverScope property into EquinoxAspectsLoadTimeWeaver.

    weaverScope=BUNDLE

    If you declare EquinoxAspectsLoadTimeWeaver like this :

    <bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
      <property name="weaverScope" value="BUNDLE" />
    </bean>

    It means that the weaving is done ONLY for the classes belong to the bundle which declare Spring bean EquinoxAspectsLoadTimeWeaver. BUNDLE weaverScope is the default value, so you can write just :

    <bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
    </bean>

    weaverScope=APPLICATION

    If you declare EquinoxAspectsLoadTimeWeaver like this :

    <bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
      <property name="weaverScope" value="APPLICATION" />
    </bean>

    It means that the weaving is done for the whole classes of each bundles.

    SpringWeaver (0.1.2) – JPA Eclipselink – Example

    You can find a basic sample with EclipseLink and EquinoxAspectsLoadTimeWeaver (0.1.2) on Dynaresume SVN – SpringWeaver. You will find a Domain bundle and JPA Bundle. Here the entityManagerFactory bean decalaration :

    <!-- entityManagerFactory created before DAO -->
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    ...
    		<property name="loadTimeWeaver">
    			<bean
    				class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
    				<property name="weaverScope" value="APPLICATION" />
    			</bean>
    		</property>
    	</bean>

    Here the Spring XML file module-context.xml used into the bundle JPA org.dynaresume.dao.jpa.eclipselink :

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    
    	<!-- entityManagerFactory created before DAO -->
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="persistenceUnitName" value="dynaresume" />
    		<property name="dataSource" ref="dataSource" />
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
    				<property name="database" value="H2" />
    				<property name="generateDdl" value="false" />
    				<property name="showSql" value="true" />
    			</bean>
    		</property>
    		<property name="loadTimeWeaver">
    			<bean
    				class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver">
    				<property name="weaverScope" value="APPLICATION" />
    			</bean>
    		</property>
    	</bean>
    
    	<bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa"></bean>
    
    	<bean
    		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
    	<tx:annotation-driven transaction-manager="txManager" />
    
    	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="entityManagerFactory" />
    	</bean>
    
    </beans>

    Into [step2], I explain how test and describe the content of SpringWeaver (0.1.2) – JPA Eclipselink – Example.

    SpringWeaver (0.1.2) – Recipe

    To use SpringWeaver (0.1.2), you must follow several rules :

    1. only the bundle org.eclipse.equinox.weaving.hook from Equinox Aspects is required. Indeed this Equinox Hook (fragment linked to org.eclipse.osgi bundle) doesn’t depends on AspectJ. So you can use SpringWeaver without AspectJ.
    2. org.eclipse.equinox.weaving.springweaver bundle must be started (Start level=3) BEFORE the another bundles which use Domain classes which must be woven. Once a Class is loaded, woven cannot be applied.
    3. the launch must add to the JVM parameters the content :
      -Dosgi.framework.extensions=org.eclipse.equinox.weaving.hook
    4. with PDE, the bundle org.eclipse.osgi must be imported (as binary) into the workspace.
    5. don’t use <context:load-time-weaver like this :
      <context:load-time-weaver class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver"/>
    6. DAO must be declared AFTER the entityManagerFactory, otherwise the Domain classes will be loaded (by the DAO) before the creation of the entityManagerFactory and Domain classes will not be woven.

    You can read [step2] article.

    About these ads
  1. Matthias
    juin 7, 2010 à 12:34

    Hi Angelo,

    I’m currently facing ltw problems, so i found your site.

    Now i’m trying to use Martin Lipert LTW, but i i get this:

    osgi> start 72
    org.osgi.framework.BundleException: The bundle could not be resolved. Reason: Missing Constraint: Import-Package: org.eclipse.equinox.service.weaving; version= »0.0.0″

    I have no idea which bundle contains org.eclipse.equinox.service.weaving, could didn’t tell me either…

  2. juin 7, 2010 à 12:50

    Hi Matthias

    Equinox Aspect http://www.eclipse.org/equinox/incubator/aspects/index.php provides the he bundle org.eclipse.equinox.weaving.hook which provides the package org.eclipse.equinox.service.weaving. I have explained how get this bundle and how use it into the step2 http://angelozerr.wordpress.com/2010/04/30/springweaver_step2/

    Regards Angelo

  3. Hugues Malphettes
    septembre 13, 2010 à 4:40

    Angelo,
    Many thanks for this post and the source code on svn.
    I needed to port a webapp that uses spring-aspectj-AOP to a web-bundle running on the top of equinox.
    It just worked right away.
    Cheers,
    Hugues

    • septembre 13, 2010 à 5:00

      Hughes,

      I’m happy that Springweaver 0.1.2 please you. Don’t hesitate to post your comments if you have some troubles.

      Regards Angelo

  4. Peter
    août 3, 2011 à 8:29

    Hi Angelo,

    I was facing the same problem as you did with my domain classes not being enhanced because the resided in a separate bundle. There is a solution to the problem that also works with the 0.1.1 version of the springweaver bundle. The idea is like this:
    1. Add a fragment to the domain bundle with a spring context. Define the org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver bean there and publish the bean as a OSGi service.
    2. In the bundle where the entity manager factory is defined import the weaver bean as OSGi service and use it in the jpa definition:

    3. Make sure the domain bundle is auto-startet

    This works at least if you only have one domain bundle.

    Cheers,
    Peter

    • août 3, 2011 à 11:40

      Hi Peter,

      Thank a lot for your comment. Indeed fragment works, but if I understand, you must create an OSGi fragment per Domain bundles?

      Regards Angelo

  5. janvier 3, 2012 à 12:07

    Hi Angelo,

    I tried your weaver bridge, but my domain classes are not woven.
    Would you please take a look at my helloworld in order to see what goes wrong?
    I sent you a gmail invitation (cmordant1@gmail.com)

    Regards, Charlie

    • janvier 3, 2012 à 1:26

      Hi Charlie,

      I’m sorry but I have not time to see your problem. hope you will understand.

      Good lucks!

      Regards Angelo

      • janvier 3, 2012 à 10:41

        Thank you Angelo

        After many hours of investigation, it seems that equinox 3.7 or eclipselink 2.3.0 have’nt got the same behaviour as you described, my domain class is definitely not of the type of persistenceweaved neither with the 0.1.1 and Peter’s workaround, neither with yours (I verified in debugging mode that the scope was Application, and dynamic imported my domain packages!).
        Or it may be spring tx or atomikos in my project that changes the behaviour…
        I opted for static weaving process: http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_(ELUG)#Example_19-37.

        Do you know if there is a new alternative, with 4.3.0 osgi spec for example.

        Regards

  6. janvier 4, 2012 à 1:29

    Hi Charlie,

    I’m really sorry, I cannot help you-( I don’t remember very well what I have developped.

    Regards Angelo

  1. avril 30, 2010 à 1:55

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Suivre

Recevez les nouvelles publications par mail.

Rejoignez 169 autres abonnés

%d blogueurs aiment cette page :