Skip to content

Maven and Gradle Setup

Martin Ledvinka edited this page May 27, 2024 · 1 revision

JOPA is published in Maven central, so introducing JOPA into a project built by Maven or Gradle consists of adding a dependency on jopa-impl and one of the OntoDriver implementations.

Dependencies

The jopa-impl artifact represents the core implementation of JOPA and depends on the JOPA API. Add the following dependency into pom.xml:

<dependency>
    <groupId>cz.cvut.kbss.jopa</groupId>
    <artifactId>jopa-impl</artifactId>
</dependency>

Then, add one of the OntoDriver implementations:

<dependency>
    <groupId>cz.cvut.kbss.jopa</groupId>
    <artifactId>ontodriver-jena</artifactId>
    <!-- OR <artifactId>ontodriver-owlapi</artifactId> -->
    <!-- OR <artifactId>ontodriver-rdf4j</artifactId> -->
</dependency>

Similarly, for Gradle:

repositories {
    mavenCentral()
}

dependencies {
    implementation "cz.cvut.kbss.jopa:jopa-impl:2.0.0"
    implementation "cz.cvut.kbss.jopa:ontodriver-rdf4j:2.0.0"
}

Refer to the JOPA Gradle example for a working setup.

Snapshots

Occasionally, pre-release snapshots of JOPA are published. This happens mainly for large features or major releases that may bring breaking changes and need some beta-testing before the actual release. These snapshots are published at the Maven central snapshot repository. To use them, a corresponding repository needs to be registered in the application's pom.xml. For example:

<repository>
  <id>central-snapshots</id>
  <url>https://oss.sonatype.org/content/repositories/snapshots</url>
  <releases>
    <enabled>false</enabled>
  </releases>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
</repository>

Note that to use a snapshot version of the JOPA Maven plugin, the snapshot repository needs to be registered also under pluginRepositories.

Another option besides the Maven central snapshots is using the KBSS research group's Maven repository at https://kbss.felk.cvut.cz/m2repo/. Setup is the same as for the Maven central snapshots.

Prior to version 2.0.0

Prior to version 2.0.0, it was necessary to weave entity classes with AspectJ so that change tracking and lazy loading worked correctly. This is no longer necessary. The following section is here only for reference for legacy deployments.

AspectJ

JOPA uses AspectJ aspects to get notified of calls to entity getters and setters. The getter aspect is important for lazy loading support. The setter aspect allows JOPA to track transactional changes to entities.

Prior to version 0.9.11, there was one scenario in which AspectJ may have been skipped - if the entities did not require lazy loading (fairly common) and if changes during transactions needed not be tracked. For instance, if the application used DAOs and update implementations looked something like

public void update(T entity) {
// em is EntityManager instance
em.getTransaction().begin();
em.merge(entity);
em.getTransaction.commit();
}

i.e., simply put, if there were no entity setter calls during a transaction, then the aspects not firing caused no harm. However, since rewriting the BeanListenerAspect to Java, AspectJ processing is required always, otherwise, the application will fail with ClassCastException when trying to cast entities to Manageable, defined by the aspect.

Thus, AspectJ weaving has to be done either at compilation time or at load time. The following sections show two examples of setting up AspectJ weaving on a project using JOPA.

Compile-time Weaving

The AspectJ Maven plugin is used to weave entity classes at compile time. The following snippet shows how to set up the plugin to weave classes in pom.xml:

<build>
   <plugins>
      <plugin>
         <groupId>dev.aspectj</groupId>
         <!-- <groupId>org.codehaus.mojo</groupId> could be used as well, but it does not support JDK 17+ -->
         <artifactId>aspectj-maven-plugin</artifactId>
         <configuration>
            <complianceLevel>11</complianceLevel>
            <source>11</source>
            <target>11</target>
            <aspectLibraries>
               <aspectLibrary>
                  <!-- This specifies where the aspects are -->
                  <groupId>cz.cvut.kbss.jopa</groupId>
                  <artifactId>jopa-impl</artifactId>
               </aspectLibrary>
            </aspectLibraries>
         </configuration>
         <dependencies>
           <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjtools</artifactId>
           </dependency>
         </dependencies>
         <executions>
           <execution>
             <id>compile</id>
             <phase>process-classes</phase>
             <goals>
               <!-- use this goal to weave source classes -->
               <goal>compile</goal>
             </goals>
             </execution>
             <execution>
               <!-- Split into two executions to ensure AJC runs AFTER regular compile in tests as well -->
               <!-- This is necessary if there are entity classes declared in test sources -->
               <id>test-compile</id>
               <phase>process-test-classes</phase>
               <goals>
                 <!-- use this goal to weave test classes -->
                 <goal>test-compile</goal>
               </goals>
             </execution>
           </executions>
       </plugin>
       <!-- other plugins -->
   </plugins>
</build>

Note that it is highly recommended to use the AspectJ Maven plugin with groupId dev.aspect. The original MojoHaus AspectJ Maven plugin is no longer maintained and does no support Java 17 and later.

Load-time Weaving

As of JOPA 0.10.5, it is also possible to use load-time weaving to weave JOPA aspects into project entities.

The following snippets show how to set up load time weaving.

Command line application (e.g. Spring Boot):

java -javaagent:path/to/aspectj-weaver-1.9.20.jar -jar application.jar

Maven exec plugin:

<groupId>dev.aspectj</groupId>
    <artifactId>exec-maven-plugin</artifactId>
        <version>1.13.1</version>
        <executions>
            <execution>
                <id>default-cli</id>
                <configuration>
                     <executable>java</executable>
                            <arguments>
                                <argument>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar</argument>
                                <argument>-classpath</argument>
                                <classpath/>
                                <argument>cz.cvut.kbss.jopa.example01.Example</argument>
                                <argument>manual</argument>
                            </arguments>
                </configuration>
            </execution>
        </executions>
    </artifactId>
</groupId>

Weaving tests with maven-surefire-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <argLine>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar</argLine>
    </configuration>
</plugin>

Note that for Java 16 and later, --add-opens java.base/java.lang=ALL-UNNAMED should be passed among JVM parameters.