Skip to Content

If you consider using EclipseLink as the JPA provider for your application, give the area of weaving careful thought. Weaving is a bytecode manipulation technique that EclipseLink uses for various optimizations in the handling of JPA entities, including lazy loading of relations and attributes, and change detection. While you could, in principle, run EclipseLink completely without bytecode weaving, you wouldn’t do so in a production environment as it improves the performance of your application significantly.

SAP NetWeaver AS Java doesn’t allow any bytecode modifications at class loading time, so you have to perform the weaving earlier when actually compiling the application – a technique referred to as “static weaving”. EclipseLink provides an Ant task for that purpose, which you can integrate into the build process. Users of the SAP NetWeaver Development Infrastructure (NWDI) might find this task rather challenging, mainly because the knowledge about the build extension mechanism isn’t widely spread. In this blog, I’ll show you step-by-step how to include EclipseLink’s static weaving into the NWDI component build.

Note: In more general terms you can consider \ this description an example for integrating an arbitrary Ant task into the NWDI component build.

Implement EclipseLink’s Static Weaving as a Build Infrastructure Extension

In the NWDI, each Development Component (DC) has a dependency to a particular Build Plugin DC that implements the build process for that DC type. This dependency is set automatically when you create a new DC in the SAP NetWeaver Developer Studio.

A Build Infrastructure Extension DC allows you extend the predefined build process, thus adapting it to your specific needs. To enable these changes for the build of a particular DC, simply add a build-time dependency on the Build Infrastructure Extension DC to your DC. The Build Infrastructure Extension can contain Java code or Apache Velocity macros. An extension DC also contains a special descriptor file for the build plugin framework to define the extension.

EclipseLink’s Ant Task for Static Weaving

As a prerequisite for integrating EclipseLink’s weaving into the NWDI component build, you should get an EclipseLink archive (including the matching javax.persistence API) of exactly the same version that is deployed on your application server. Note that a version mismatch might cause problems with the woven classes. You can download EclipseLink from this location: http://www.eclipse.org/eclipselink/downloads/index.php

The eclipselink.jar file contains an Ant task that can weave a set of already compiled java classes: org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask. See EclipseLink’s weaving documentation for details on how to use the Ant task.

Create a Build Infrastructure Extension DC

In order to integrate the static weaving with the NWDI component build, you have to create a Build Infrastructure Extension DC, which is invoked immediately after the regular Java build and which simply calls EclipseLink’s weaving task:

  1. Choose File → New → Other and select Development Infrastructure → Development Component to create a new DC Project.
  2. Choose DC Build → Build Infrastructure Extension as Development Component type.
  3. Select the software component for the Build Infrastructure Extension DC.
    In this example, I use LocalDevelopment → MyComponents.
  4. Provide vendor and name for the DC.
    I use demo.sap.com as vendor and el_static_weaving as name.
  5. Choose Finish.
  6. As a result, you should have a folder structure like this:

  7. /wp-content/uploads/2010/08/el_stat_weav_struct_143390.png
  8. Note: You might have to disable the filter on the “.* resources” in order to see the .bpfext file.
  9. Copy the following JAR files from the unpacked EclipseLink download archive to the bp/lib/java\ folder:
    • eclipselink.jar
    • javax.persistence_<version>.jar
  1. Edit the .bpfext descriptor to define an EclipseLink static weaving extension for the Java compiler with a special postprocessor macro (see below). In case that you chose another name or vendor for your extension DC, note that you need to adapt the macro definition accordingly (where highlighted).
  2. <?xml version="1.0" encoding="UTF-8"?>
    <technologies version="1">
      <technology name="demo.sap.com/el_static_weaving">
        <uses>sap.com/tc/bi/javatech</uses>
        <generators>
          <extension
            type="demo.sap.com~el_static_weaving"
            extends="sap.com~javac"
            implementation-type="macro"
            implementation-after="EclipseLinkWeaving"/>
        </generators>
      </technology>
    </technologies>
  3. This tells the Build Plugin Framework to execute a macro called EclipseLinkWeaving with a predefined signature after each invocation of the Java compiler.

  4. Edit the Velocity macro file demo.sap.com_el_static_weaving.vm to define the EclipseLinkWeaving macro:
  5. #macro(EclipseLinkWeaving $input $output $used $params)
        ## define task
        ## Use antBase to avoid duplicate definitions and
        ## to put the definition in the project itself.
        $antBase.taskdef("staticweaver", "org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask")

        ## find persistence.xml in source folders
        #set($persistenceXMLpath = false)  
        #set($inputpaths = $input.get("default"))
        #foreach($inputpath in $inputpaths)
            #if ($dc_util.isFile("${inputpath}/META-INF/persistence.xml"))
                #set($persistenceXMLpath = $inputpath)
            #end
        #end

        ## copy persistence.xml and orm.xml to output folder
        ## static weaver needs them
        #set ($outputpath = $output.get("default"))
        <copy todir="${outputpath}/META-INF" verbose="true" failonerror="true">
            <fileset dir="${persistenceXMLpath}/META-INF">
                <include name="persistence.xml"/>
                <include name="orm.xml"/>
            </fileset>
        </copy>

        ## invoke staticweaver ant task
        ## loglevel set toFINEST to produce some output
        #StartTimer()
        <staticweaver
                source="${outputpath}"
                target="${outputpath}"
                loglevel="FINEST">
            <classpath>
            #set ($usedpaths = $used.get("default"))
            #foreach($usedpath in $usedpaths)
                <path location="${inputpath}"/>
            #end
            </classpath>
        </staticweaver>
        #ShowTimer("EclipseLink static weaving")

        ## remove persistence.xml and orm.xml to avoid build warning (duplicates)
        <delete verbose="true">
            <fileset dir="${outputpath}/META-INF">
                <include name="persistence.xml"/>
                <include name="orm.xml"/>
            </fileset>
        </delete>
    #end

  6. This macro renders the <staticweaver> task to an Ant build script using the same default input path (i.e. package folders defined for the DC), the same default used path (or “classpath”) and the same output path that the Java compiler used.

  7. For more info on the Velocity Template Language, refer to http://velocity.apache.org/.

  8. In the Component Properties view of the Build Infrastructure Extension, go to the Folders tab and remove the src folder. This folder is actually empty and would cause a warning in the build.
  9. /wp-content/uploads/2010/08/el_stat_weav_remove_src_143391.png
  10. Build the DC.

Use the Build Infrastructure Extension for Your Application

Once you have defined the Build Infrastructure Extension for EclipseLink’s weaving, you can use it to add static weaving to the build of your JPA application DC:

  1. In the Component Properties view of the JPA application, add a build-time dependency on the def public part of the Build Infrastructure Extension DC. This public part has been added automatically when creating the extension.
  2. /wp-content/uploads/2010/08/el_stat_weav_add_dep_143392.png
  3. Build the DC.
  4. Check the build log. There should be some output produced by the weaving task indicating that the weaving actually worked (see below). Any error that might have occurred would also be reported here.
  5. [copy] Copying 1 file to C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF
    [copy] Copying C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\DCs\\demo.sap.com\\my_jpa_app\\_comp\\ejbModule\\META-INF\\persistence.xml
    to C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF\\persistence.xml
    [staticweaver] [EL Finest]: 2010-08-05 14:03:33.857
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--property=eclipselink.jpa.uppercase-column-names; default value=false
    [staticweaver] [EL Finer]: 2010-08-05 14:03:33.873
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Searching for default mapping file in file:/C:/temp/nwds/
    workspace.jdi/LocalDevelopment/t/1E783F30932B07B16D7E78DDA43001D5/classes/
    [staticweaver] [EL Finer]: 2010-08-05 14:03:33.873
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Searching for default mapping file in file:/C:/temp/nwds/
    workspace.jdi/LocalDevelopment/t/1E783F30932B07B16D7E78DDA43001D5/classes/
    [staticweaver] [EL Config]: 2010-08-05 14:03:33.998
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The access type for the persistent class [class entities.EntityB]
    is set to [FIELD].
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The access type for the persistent class [class entities.EntityA]
    is set to [FIELD].
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The target entity (reference) class for the one to one mapping
    element [field b] is being defaulted to: class entities.EntityB.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The alias name for the entity class [class entities.EntityB]
    is being defaulted to: EntityB.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The column name for element [field id] is being defaulted
    to: ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The alias name for the entity class [class entities.EntityA]
    is being defaulted to: EntityA.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The column name for element [field id] is being defaulted to:
    ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The primary key column name for the mapping element
    [field b] is being defaulted to: ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The foreign key column name for the mapping element
    [field b] is being defaulted to: B_ID.
    [staticweaver] [EL Finer]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Class [entities.EntityB] registered to be processed by weaver.
    [staticweaver] [EL Finer]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Class [entities.EntityA] registered to be processed by weaver.
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.7
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Begin weaver class transformer processing class
    [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved persistence (PersistenceEntity) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved change tracking (ChangeTracker) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved lazy (ValueHolder indirection) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved fetch groups (FetchGroupTracker) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--End weaver class transformer processing class [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Begin weaverclass transformer processing class [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved persistence (PersistenceEntity) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved change tracking (ChangeTracker) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved fetch groups (FetchGroupTracker) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--End weaver class transformer processing class [entities/EntityB].
    [timer] EclipseLink static weaving finished in 1.045 seconds

    [delete] Deleting 1 files from C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\
    t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF
    [delete] Deleting C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\
    t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF\\persistence.xml
  6. A slight warning: Check the build log, especially the[staticweaver] output, carefully. If EclipseLink didn’t detect any entities (for example due to a missing persistence.xml file), the build would still succeed but the entities wouldn’t be woven – and thus not be mentioned in the [staticweaver] log.

Further Information

Build Plugin Framework Reference for NWDI

If you have a SAP Service Marketplace user, you can refer to SAP Support Note 1061467 to get more information on the Build Plugin Framework.

Summary

That’s basically all you have to do to add EclipseLink’s static weaving to the NWDI component build:

  1. Create a Build Infrastructure Extension for static weaving.
  2. Add a dependency on the extension to your application DC.

Admittedly, creating the Build Infrastructure Extension is a bit tricky, but it’s a one-time-only task. Once you have the definition in place, you can use it over and over again for all your EclipseLink applications.

To report this post you need to login first.

5 Comments

You must be Logged on to comment or reply to a post.

  1. Rolf Paulsen
    Hi Sabine,

    many thanks for your detailled description. Beside its actual theme, it is one of the very few sources of information about the treasured secret of building a Build Infrastructure Extension DC (the last/only other(?) one is 2.5 yrs old: Isn ‘t it Groovy – extending the Development Component build with Groovy?). The SAP help merely tells us that these infrastructure DC types exist. E.g. it is impossible to find in SDN an “API” of the $dc_util object in the VTL macro.

    Your way works out of the boy fine in the “normal” – small to medium – case with one DC containing all entities. In our app we have the entities split over more than one DC, lets say DCa and DCb, hereby entity classes in DCb extend classes in DCa. Thus DCa is needed for weaving of DCb. Furthermore, DCa needs a reduced persistence.xml for weaving because classes from DCb are not available when building DCa since DCa does not depend on DCb.

    We will muddle through on the valuable base of your blog.

    A comment in the above mentioned blog:
    “so cool. There is much too less such contributions in the area of NWDI !”

    This seems still correct to me.

    Cheers
    Rolf

    (0) 
    1. Rolf Paulsen
      P.S.
      1. pls replace “boy” with “box” 🙂
      2. I am still looking forward to dynamic weaving which will make NetWeaver a REALLY fully JEE compliant Application Server :-))
      (0) 
    2. Sabine Heider Post author
      Hi Rolf,

      I kind of expected that your case might be more difficult 🙂 If you encounter any problems that you can’t solve, don’t hesitate to contact us and we’ll try to find a way.

      I agree with you that information about the Build Plugin Framework is sparse both in the help portal and in SDN. However, you should check out the attachments to SAP Support Note 1061467, which contain a lot of information. For example, the javadoc for the $dc_util object is also available there.

      Best regards,
      Sabine

      (0) 
      1. Rolf Paulsen
        Hi Sabine,
        the attachments to Note 1061467 are great, but it lacks the continous, thorough example like your blog.
        (BTW there is a C&P typo in the static weaving ant task – ${usedpath} instead of ${inputpath} – maybe you can edit the reference in your blog.)
        What makes things complicated in our case is that the COMPILATION PP is woven, not only the ASSEMBLY PP. So if Enitity-classes in DC B extend abstract superclass-Entities from DC A, I get an javac-compilation error in DC B “X is not abstract and does not override abstract method _persistence_shallow_clone()” because EclipseLink weaves abstract methods in DC A. This would work fine if the COMPILATION PP was not woven and DC B compiled against the unwoven classes in A.  Unfortunately the static weaving extension cannot hook easily between the packing of Compilation and Assembly. Nasty thing, but we will solve it.

        Best regards,
        Rolf

        (0) 

Leave a Reply