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

From Opentaps Wiki
Jump to navigationJump to search
Line 145: 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.

Revision as of 22:26, 5 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 keep them apart from the Java source files. 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)

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:

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

I will also need to load my persistence.xml and 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.