Difference between revisions of "Making a Persistent Class with openJPA and OSGi"

From Opentaps Wiki
Jump to navigationJump to search
 
(3 intermediate revisions by 2 users not shown)
Line 5: Line 5:
 
@Entity
 
@Entity
 
@Table(name="NOTE_DATA")
 
@Table(name="NOTE_DATA")
@Inheritance(strategy=InheritanceType.JOINED)
 
 
public class Note implements Serializable {
 
public class Note implements Serializable {
  
Line 16: Line 15:
 
      
 
      
 
     @Lob
 
     @Lob
    @Basic(fetch=FetchType.LAZY)
 
 
     @NotEmpty
 
     @NotEmpty
 
     @Column(name = "NOTE_TEXT", nullable = false)
 
     @Column(name = "NOTE_TEXT", nullable = false)
Line 40: Line 38:
 
</pre>
 
</pre>
  
Then, I need to create a META-INF/persistence.xml for this class.  Since there currently isn't one in the module, I need to create it from scratch.  These xml files are in the src/main/resources directory, to keep them apart from the Java source files.  Here's what this file looks like:
+
Then, I need to create a META-INF/persistence.xml for this class.  Since there currently isn't one in the module, I need to create it from scratch.  These xml files are in the src/main/resources directory, to follow Maven rule for project resources.  Here's what this file looks like:
 
<pre>
 
<pre>
 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
Line 63: Line 61:
 
(Ok, I cheated: I moved over the one from notes/impl/repository module and modified it for this class instead of NoteData.java)
 
(Ok, I cheated: I moved over the one from notes/impl/repository module and modified it for this class instead of NoteData.java)
  
Next, I will need to add support for persistence to my notes/domain module by modifying its pom.xml.  I need to add the openJPA plugin:
+
openJPA performs best when persistent classes have been run through the bytecode enhancer. We will not ignore this great opportunity and add enhancing step into notes/domain POM:
 
<pre>
 
<pre>
 
   <build>
 
   <build>
Line 89: Line 87:
 
</pre>
 
</pre>
  
I will also need to load my persistence.xml and make sure that the org.opentaps.notes.domain package is exported:
+
Despite the fact that META-INF/persistence.xml is common place and name for persistence descriptor we also need to add <Meta-Persistence> header to meet specs for persistence bundle. Also, make sure that the org.opentaps.notes.domain package is exported:
 
<pre>
 
<pre>
 
           <plugin>
 
           <plugin>
Line 147: Line 145:
 
         </dependency>
 
         </dependency>
 
</pre>
 
</pre>
 +
 +
The rest of the refactoring is completed by adding this dependency to other modules, and Note.java becomes a persistent class.

Latest revision as of 19:02, 6 March 2012

As I'm working with the Notes application, I decide to make the Note.java in the notes/domain module persistent, so we don't have to have a separate NoteData.java class in notes/impl/repository just for persisting.

The first step is to add the openJPA persistence markups to Note.java, which describe how the Java fields will be represented in the database:

@Entity
@Table(name="NOTE_DATA")
public class Note implements Serializable {

    private static final long serialVersionUID = -4314958909722739985L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="uuid-type4-hex")
    @Column(name = "NOTE_ID", nullable = false, length = 32)
    private String noteId;
    
    @Lob
    @NotEmpty
    @Column(name = "NOTE_TEXT", nullable = false)
    private String noteText;

    @Column(name = "CREATED_BY_USER_ID")
    private String createdByUserId;

    @Column(name = "USER_ID_TYPE")
    private String userIdType;

    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name = "SEQUENCE_NUM", nullable = false)
    private Long sequenceNum;
    
    @Column(name = "CLIENT_DOMAIN")
    private String clientDomain;
    
    @NotNull
    @Column(name = "DATE_TIME_CREATED")
    private Timestamp dateTimeCreated;
// ... etc

Then, I need to create a META-INF/persistence.xml for this class. Since there currently isn't one in the module, I need to create it from scratch. These xml files are in the src/main/resources directory, to follow Maven rule for project resources. Here's what this file looks like:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">

    <persistence-unit transaction-type="JTA" name="notes">
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
        <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/opentaps2-db-xa)</jta-data-source>
        <non-jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/opentaps2-db-none)</non-jta-data-source>

        <class>org.opentaps.notes.domain.Note</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
            <property name="openjpa.BrokerImpl" value="non-finalizing" /> 
        </properties>
    </persistence-unit>

</persistence>

(Ok, I cheated: I moved over the one from notes/impl/repository module and modified it for this class instead of NoteData.java)

openJPA performs best when persistent classes have been run through the bytecode enhancer. We will not ignore this great opportunity and add enhancing step into notes/domain POM:

   <build>
       <plugins>
           <plugin>
               <groupId>org.apache.openjpa</groupId>
               <artifactId>openjpa-maven-plugin</artifactId>
               <version>2.2.0</version>
               <configuration>
                   <includes>**/*.class</includes>
                   <excludes>**/*PK.class</excludes>
                   <addDefaultConstructor>true</addDefaultConstructor>
                   <enforcePropertyRestrictions>true</enforcePropertyRestrictions>
               </configuration>
               <executions>
                   <execution>
                       <id>enhancer</id>
                       <phase>process-classes</phase>
                       <goals>
                           <goal>enhance</goal>
                       </goals>
                   </execution>
               </executions>
           </plugin>

Despite the fact that META-INF/persistence.xml is common place and name for persistence descriptor we also need to add <Meta-Persistence> header to meet specs for persistence bundle. Also, make sure that the org.opentaps.notes.domain package is exported:

           <plugin>
               <groupId>org.apache.felix</groupId>
               <artifactId>maven-bundle-plugin</artifactId>
               <configuration>
                   <instructions>
                       <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>
                       <Export-Package>org.opentaps.notes.domain</Export-Package>
                   </instructions>
               </configuration>
           </plugin>
       </plugins>

Finally, I need to add in dependencies for building the notes/domain module with openJPA:

    <dependencies>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-jpa_2.0_spec</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-validation_1.0_spec</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>validation.api</artifactId>
            <version>${project.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

The first dependency is javax.persistence API, the second one javax.validation, and the third our own package for data validation.

Now when I build, my annotations are accepted, but I get this odd error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project notes.repository.api: Compilation failure
[ERROR] Failure executing javac, but could not parse the error:
[ERROR] An exception has occurred in the compiler (1.6.0_29). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  
after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
[ERROR] com.sun.tools.javac.code.Symbol$CompletionFailure: class file for javax.persistence.InheritanceType not found

Wow! You mean Java has bugs too?

A little searching and guessing, and it turns out that because the notes/api/repository and notes/api/services modules now use a class (Note.java) which is persistent, they need their own reference to openJPA persistence as well. So, after some trial and error, it seems that adding this dependency fixes it:

        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-jpa_2.0_spec</artifactId>
            <scope>provided</scope>
        </dependency>

The rest of the refactoring is completed by adding this dependency to other modules, and Note.java becomes a persistent class.