Table of Contents

OX2 to OX3 metal migration guide
Component definition
Aggregates
Valid values
Default value calculators on create
Callback calculators: postcreate, postmodify, postload, preremove and postremove
Converters
persistence.xml instead of configuration
JUnit test: Setting value to a combo for a composite key reference
View property

OX2 to OX3 metal migration guide

This guide is for helping to an OpenXava 2 developer to start rapidly with OpenXava 3.
OX3 will be fully compatible with OX2 and you will can run your OX2 applications using OX3, also you can develop using XML with OX3.

Component definition

The main difference between OX2 and OX3 is the format for defining components.
In OX2 we use XML, as following:
<?xml version="1.0" encoding="ISO-8859-1"?>
 
<!DOCTYPE component SYSTEM "dtds/component.dtd">
 
<component name="Teacher">
 
    <entity>
        <property name="id" type="String" key="true"
            size="5" required="true"/>
        <property name="name" type="String"
            size="40" required="true"/>
    </entity>
 
    <entity-mapping table="MYSCHOOL@separator@TEACHER">
        <property-mapping property="id" column="ID"/>
        <property-mapping property="name" column="NAME"/>
    </entity-mapping>
 
</component>

In OX3 we use Java with annotations:
package org.openxava.school.model;
 
import javax.persistence.*;
import org.openxava.annotations.*;
 
@Entity
public class Teacher {
 
    @Id @Column(length=5) @Required
    private String id;
 
    @Column(length=40) @Required
    private String name;
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
}

Now you write the logic directly in your Java class, therefore you does not need calculator for calculated properties nor method.
The object-relational mapping is done by JPA annotations. And the rest (tab and view) is a literal translation of OpenXava XML to Java annotations.

Aggregates

Aggregates do not longer exist on OX2. But you can simulate the aggregate using embeddable objects for single references, and collection of entities with cascade remove for collections.
That is, in OX2 you writes:
<entity>
    <reference name="address" model="Address"/>
</entity>
 
<aggregate name="Address">
...
</aggregate>
And in OX3 you write:
// Customer.java
@Entity
public class Customer {
 
    @Embedded
    private Address address;
 
}
 
// Address.java
@Embeddable
public class Address {
 
}
As you can see, we use the JPA Embeddable object that behaves exactly as an aggregate of OpenXava for the case of single reference.
For collection of aggregate you write using OX2:
<component name="Invoice">
 
    <entity>
        <collection name="details">
            <reference model="InvoiceDetail"/>
        </collection>
    </entity>
 
    <aggregate name="InvoiceDetail">
    ...
    </aggregate>
 
</component>
But in OX3 you write:
// Invoice.java
@Entity
public class Invoice {
 
    @OneToMany (mappedBy="invoice", cascade=CascadeType.REMOVE)
    private Collection<InvoiceDetail> details;
 
}
 
// InvoiceDetail.java
@Entity
public class InvoiceDetail {
 
}
That is, you use a collection of entities with cascade type remove, and this behaves as the collection of aggregates of OX2.

Valid values

The OX2 <valid-values/> are implemented in OX3 with Java 5 enums.
That is, in OX2 you write:
<property name="distance">
    <valid-values>
        <valid-value value="local"/>
        <valid-value value="national"/>
        <valid-value value="international"/>
    </valid-values>
</property>
Its equivalent in OX3 is:
private Distance distance;
public enum Distance { LOCAL, NATIONAL, INTERNATIONAL };
 
It has the same effect, except that:
That is, if you want to use a database of OX2 with OX3 you need to use a Hibernate Type, as following:
@org.hibernate.annotations.Type(type="org.openxava.types.Base1EnumType",
parameters={
    @Parameter(name="enumType", value="org.openxava.test.model.InvoiceDetail$ServiceType")
}
)
private ServiceType serviceType;
public enum ServiceType { SPECIAL, URGENT }
 
Base1EnumType is a Hibernate Type included in OpenXava for saving a Java 5 enum with base 1 index. In this way you go against the database of your OX2 application using OX3.

Default value calculators on create

The default-value-calculator of OX2 is available in OX3 by means of @DefaultValueCalculator annotation. But @DefaultValueCalculator does not support on-create="true" of its XML counterpart. You have to simulate the effect of this type of calculator using the JPA equivalent.
For an autogenerated id you have to use the @GeneratedValue JPA annotation. For example, in OX2 you write:
<property name="number" type="Integer" key="true" size="5" required="false">
    <default-value-calculator class="org.openxava.calculators.IdentityCalculator" on-create="true"/>
</property>
In OX3 you write:
@Id @Column(length=5)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer number;
That is, plain JPA code.
But <default-value-calculator ... on-create="true"/> is more flexible than @GeneratedValue because it admits any logic, and it can be used for not key properties. In this case you can use a @PrePersist JPA method. Let's look an example. When in OX2 you write:
<property name="oid" type="String" key="true" hidden="true">
    <default-value-calculator
        class="org.openxava.test.calculators.InvoiceDetailOidCalculator"
        on-create="true"/>
</property>
 
Where InvoiceDetailOidCalculator has a custom logic for generated the value. This can be easily translate to OX3 adding the next method to your POJO:
@PrePersist
private void calculateOID() {
    oid = invoice.getYear() + ":" + invoice.getNumber() + ":" + System.currentTimeMillis();
}
 
In this case the logic of calculatedOID method is the same of the InvoiceDetailOIDCalculator. Again, you can see as we are using plain JPA code.

Callback calculators: postcreate, postmodify, postload, preremove and postremove

Instead of <postcreate-calculator/>, <postmodify-calculator/>, <postload-calculator/>, <preremove-calculator/> and <postremove-calculator/> in OX3 you use the standard JPA callback methods, that is, methods in your entity annotated with @PrePersist, @PostPersist, @PreRemove, @PostRemove, @PreUpdate, @PostUpdate and @PostLoad.
For example, if you have a collection as this one in an Invoice component:
<collection name="details">
    <reference model="InvoiceDetail"/>
    <postremove-calculator
        class="org.openxava.test.calculators.DetailPostremoveCalculator"/>
</collection>
With this calculator class:
package org.openxava.test.calculators;
 
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
public class DetailPostremoveCalculator implements IModelCalculator {
 
    private IInvoice invoice;
 
    public Object calculate() throws Exception {
        invoice.setComment(invoice.getComment() + "DETAIL DELETED");
        return null;
    }
 
    public void setEntity(Object model) throws RemoteException {
        this.invoice = (IInvoice) model;
    }
 
}
In OX3 you only need to have a method as this one in the InvoiceDetail class:
@PostRemove
private void postRemove() {
    invoice.setComment(invoice.getComment() + "DETAIL DELETED");
}
 
In this case easier than in OX2.

Converters

The useful OpenXava converters are not available in OX3. But, don't worry, we can use the Type of Hibernate, that provides almost all functionality of OpenXava converters.
Look at Hibernate Reference about Type,
Hibernate Type has some little drawback over classic OX converter:

persistence.xml instead of configuration

In the build.xml the property 'configuration' is not longer used. Now instead of properties files we can comment and uncomment code in persistence.xml in order to work with several configuration, in this way:
    <!-- Tomcat + Hypersonic -->
    <persistence-unit name="default">
        <non-jta-data-source>java:comp/env/jdbc/MySchoolDS</non-jta-data-source>
        <class>org.openxava.session.GalleryImage</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        </properties>
    </persistence-unit>
 
    <!-- JBoss + Hypersonic
    <persistence-unit name="default">
        <non-jta-data-source>java:/MiEscuelaDS</non-jta-data-source>
        <class>org.openxava.session.GalleryImage</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        </properties>
    </persistence-unit>
    -->
 
    <!-- WebSphere + AS/400
    <persistence-unit name="default">
        <non-jta-data-source>jdbc/MiEscuelaDS</non-jta-data-source>
        <class>org.openxava.session.GalleryImage</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.DB2400Dialect"/>
            <property name="hibernate.show_sql" value="false"/>
        </properties>
    </persistence-unit>
    -->
 
Here we have 3 configuration and we can active one of them easily only commenting and uncommenting.

JUnit test: Setting value to a combo for a composite key reference

In OX3 this is the way to put value to a combo with composite key:
Shipment shipment = (Shipment) Shipment.findAll().iterator().next();
setValue("shipment.KEY", toKeyString(shipment));
 
As you see you have to use toKeyString() method (included in ModuleTestBase), and not the toString() method of the POJO.
This technique also works with OX2.

View property

View properties does not exist in OX3. But it's easy to simulate them using transient properties in your model.
That is, in OX2 you write:
<view>
    <property name="deliveredBy">
        <valid-values>
            <valid-value value="employee"/>
            <valid-value value="carrier"/>
        </valid-values>
        <default-value-calculator
             class="org.openxava.calculators.IntegerCalculator">
            <set property="value" value="0"/>
        </default-value-calculator>
    </property>
 
    <property-view property="deliveredBy">
        <on-change class="org.openxava.test.actions.OnChangeDeliveryByAction"/>
    </property-view>
    ...
</view>
And now using OX3 you will write:
@Transient
@DefaultValueCalculator(value=EnumCalculator.class,
    properties={
        @PropertyValue(name="enumType", value="org.openxava.test.model.Delivery$DeliveredBy")
        @PropertyValue(name="value", value="CARRIER")
    }
)
@OnChange(OnChangeDeliveryByAction.class)
private DeliveredBy deliveredBy;
public enum DeliveredBy { EMPLOYEE, CARRIER }
 
With the same effect.