Migración

¿Cómo actualizar tu proyecto a la última versión de OpenXava?

  • Descarga la última distribución de OpenXava y descomprímela en un lugar nuevo.
  • Si tu versión de OpenXava actual es anterior a la 5.0 crea un proyecto Java nuevo llamado Addons en tu workspace usando Eclipse.
  • Para tu Eclipse.
  • Borra los proyectos Addons (a partir de v5.0) y OpenXava de tu workspace.
  • Copia los proyectos Addons y OpenXava desde el workspace del nuevo OpenXava al tuyo.
  • Arranca tu Eclipse.
  • Haz un Build All (Ctrl-B)
  • Ejecuta la tarea ant actualizarOX de tu proyecto.
  • Refresca (con F5) tu proyecto.
  • Revisa las intrucciones que siguen.
  • Si tu aplicación falla:
    • Para el Tomcat y borra las carpetas work y temp (dentro del Eclipse haz un Clean Tomcat Work Directory... en tu servidor en la vista Servers).
    • Quita tu aplicación del Tomcat y vuélvela a añadir.

Para migrar de OpenXava 5.7.1 a OpenXava 5.8

Módulos sin filas empiezan ejecutando la acción nuevo (para pruebas JUnit)

Deberías tocar las pruebas JUnit con módulos sin filas, porque ahora empiezan en modo detalle. Por ejemplo, deberías cambiar un código como este:
public void testCrearExamenConAlMenosUnaPregunta() throws Exception {
  assertListRowCount(0); // AHORA ESTA LÍNEA FALLA
  execute("CRUD.new");
  setValue("nombre", "ADMISIÓN");
  execute("CRUD.save");
  ...
}
Si el módulo no tiene filas, ahora empieza en modo detalle por tanto la primera línea fallará. Podemos cambiar a modo lista al principio:
public void testCrearExamenConAlMenosUnaPregunta() throws Exception {
  execute("Mode.list"); // AÑADE ESTA LÍNEA
  assertListRowCount(0);
  execute("CRUD.new");
  setValue("nombre", "ADMISIÓN");
  execute("CRUD.save");
  ...
}
O si tu prueba va directamente al modo detalle, como en este ejemplo, simplemente quita la primera parte de la prueba:
public void testCrearExamenConAlMenosUnaPregunta() throws Exception {
  // assertListRowCount(0); // QUITA ESTA LÍNEA
  // execute("CRUD.new"); // QUITA ESTA LÍNEA
  setValue("nombre", "ADMISIÓN");
  execute("CRUD.save");
  ...
}

Para migrar de OpenXava 5.7 a OpenXava 5.7.1

No hay consideraciones.

Para migrar de OpenXava 5.6.1 a OpenXava 5.7

Acción List.changeConfigurationName renombrada como List.changeConfiguration (para pruebas JUnit)

La acción de lista List.changeConfigurationName ahora es List.changeConfiguration, por tanto si compruebas todas las acciones presentes en tus pruebas JUnit, has de modificar el nombre de esta acción:
private String [] accionesLista = {
  "Mode.detailAndFirst",
  "Mode.split",
  "List.filter",
  "List.orderBy",
  "List.viewDetail",
  "List.hideRows",
  "List.sumColumn",
  // "List.changeConfigurationName" // QUITA ESTA ENTRADA
  "List.changeConfiguration" // AÑADE ESTA ENTRADA
};
assertActions(accionesLista);

Propiedades por defecto mejoradas para lista y colecciones (para pruebas JUnit)

Hasta ahora cuando @Tab para la lista, o @ListProperties para las colecciones, se omite por defecto OpenXava muestra todas las propiedades planas de la entidad. A partir de v5.7 cuando @Tab/@ListProperties no está presente las propiedades a mostrar son las planas, los ids de las referencias, el nombre, descripción o título de las referencias o si no está presente la primera propiedad no id de la referencia. Además, las propiedades planas que son oids se excluyen.
Por ejemplo, si tenemos esta clase sin @Tab:
@Entity
public class Factura {
 private int ano;
 private int numero;
 private Date fecha;
 @ManyToOne
 private Cliente cliente;
 
 @Stereotype("ARCHIVOS") @Column(length=32)
 private String archivos;
 
 ...
}
En versiones anteriores hubiéramos obtenido: ano, numero, fecha, archivos
En v5.7 obtenemos: ano, numero, fecha, cliente.numero, cliente.nombre
Si tienes pruebas JUnit contra entidades sin @Tab puede que tengas que adaptarlas.

@NewAction ya no sirve para definir la acción de añadir en las colecciones @OneToMany convencionales

Desde v5.7 las colecciones @OneToMany sin cascade REMOVE tienen disponible a la vez la acción 'Nuevo' para crear nuevos elementos y la acción 'Añadir' para añadir elementos escogiendo entre los ya existentes. Antes de v5.7 solo la acción 'Añadir' estaba disponible y podía definirse con @NewAction. Ahora tenemos una nueva anotación, @AddAction, para la acción 'Añadir' y usamos la vieja @NewAction solo para la acción 'Nuevo'.
Deberías cambiar @NewAction por @AddAction en la colecciones sin cascade REMOVE. Cambia:
@NewAction("Factura.anadirAlbaranes")
@OneToMany(mappedBy="factura")
private Collection<Albaran> albaranes;
Por:
@AddAction("Factura.anadirAlbaranes")
@OneToMany(mappedBy="factura")
private Collection<Albaran> albaranes;

Colecciones de entidades sin REMOVE cascade permiten editar los elementos (para pruebas JUnit)

No necesitas cambiar tu código de aplicación, simplemente adaptar tus pruebas JUnit cambiando:
execute("Collection.view", "row=1,viewObject=xava_view_customers");
Por:
execute("Collection.edit", "row=1,viewObject=xava_view_customers");
Fíjate que ahora no es "Collection.view" sino "Collection.edit".

Optimizadas las etiquetas automáticas para las referencias en la lista (para pruebas JUnit)

Cuando en un lista tenemos un propiedad de una referencia y la propiedad se llama "nombre", "descripcion" o "titulo", el nombre de la propiedad se omite, simplemente se usa el nombre de la referencia. Es decir, en lugar de "Nombre de Cliente" ahora es solamente "Cliente". Esto no afecta al código de tu aplicación en absoluto, pero si verificas las etiquetas de alguna lista en tus pruebas JUnit, deberás de adaptarlo.
Cambia esto:
assertLabelInList(4, "Nombre de Cliente");
Por esto:
assertLabelInList(4, "Cliente");

Para migrar de OpenXava 5.6 a OpenXava 5.6.1

No hay consideraciones.

Para migrar de OpenXava 5.5.1 a OpenXava 5.6

La acción ExtendedPrint.myReports ya no está disponible por defecto (para pruebas JUnit)

Por lo tanto compruebas todas las acciones presentes en tu prueba JUnit, tendrás que modificarlo eliminando ExtendedPrint.myReports de la lista:
private String [] accionesLista = {
    "Print.generatePdf",
    "Print.generateExcel",
    // ELIMINA ESTA LÍNEA "ExtendedPrint.myReports",
    "CRUD.new",
    "CRUD.deleteSelected",
    ...
};
assertActions(accionesLista);
Aunque la acción no esté disponible por defecto, todavía existe en OpenXava y funciona perfectamente. De hecho, hay un nuevo controlador TypicalExtendedPrint para facilitar su uso. Si quieres continuar usando la funcionalidad Mis informes cambia Typical por TypicalExtendedPrint en tu aplicacion.xml y controladores.xml, incluso lo puedes declarar como controlador por defecto.

Nueva acción en lista (para pruebas junit)

La lista tiene una nueva acción disponible (List.changeConfigurationName), por lo tanto si compruebas todas las acciones presentes en tu prueba junit, tendrás que modificarlo para tener en cuenta la nueva acción "List.changeConfigurationName":
private String [] accionesLista = {
  "Mode.detailAndFirst",
  "Mode.split",
  "List.filter",
  "List.orderBy",
  "List.viewDetail",
  "List.hideRows",
  "List.sumColumn",
  "List.changeConfigurationName" // AÑADE ESTA ENTRADA
};
assertActions(accionesLista);

Para migrar de OpenXava 5.5 a OpenXava 5.5.1

Necesario llamar a super dentro de setUp() de las pruebas antes de usar JPA

A partir de v5.5.1 la inicialización de JPA en las pruebas ModuleTestBase se hace en el método setUp(), por lo que si usas JPA dentro de un método setUp() has de llamar a super antes. Es decir, si tienes un código como este en tu prueba:
protected void setUp() throws Exception {
    crearEntidadesUsandoJPA(); // Ahora falla, porque JPA todavía no está inicializado
    super.setUp();
}
Cámbialo por:
protected void setUp() throws Exception {
    super.setUp(); // JPA se incializa aquí
    crearEntidadesUsandoJPA();
}

Para migrar de OpenXava 5.4.1 a OpenXava 5.5

Los combos para @DescriptionsList ya no son selects de HTML (sólo si usas el API de HtmlUnit)

Los combos para @DescriptionsList ahora se crean usando un input text de HTML más algo de código JavaScript y CSS para simular un combo. Esto no requiere ningún cambio en el código de tu aplicación, ni siquiera has de cambiar el código de tus pruebas jUnit si sólo usas los métodos de ModuleTestBase. Sin embargo, si usas el API de HtmlUnit directamente, por ejemplo con getHtmlPage() o getWebClient() en tus pruebas, y manejas un combo de un @DescriptionList. En ese caso tienes que adaptar tu código, cambiando:
form.getSelectByName("ox_MiAp_MiModulo__miReferencia___id").setSelectedAttribute("ElValor", true);
Por:
HtmlInput comboInput = form.getInputByName("ox_MiAp_MiModulo__miReferencia___id");
comboInput.setValueAttribute("ElValor");
((HtmlInput) comboInput.getPreviousElementSibling()).setValueAttribute("Algo"); // Un truco para evitar que JavaScript borre el valor real
((HtmlInput) comboInput.getNextElementSibling()).setValueAttribute("Algo"); // Un truco para evitar que JavaScript borre el valor real

Para migrar de OpenXava 5.4 a OpenXava 5.4.1

No hay consideraciones.

Para migrar de OpenXava 5.3.2 a OpenXava 5.4

Iconos en lugar de imágenes para las acciones

A partir de v5.4 las acciones estándar de OpenXava usan iconos de Material Design Icons en vez de imágenes gif o png. El atributo imagen de <accion/> en controllers.xml continúa funcionando como siempre, sin embargo tenemos un nuevo atributo icono que es el que se usa en las acciones estándar. El efecto es que en tu aplicación todas las acciones estándar usaran los nuevos iconos monocromo y tus acciones propias usarán las vieja acciones en color con imágenes gif y png. Esto podría quedar un poco feo, para arreglarlo cambia imagen por icono en tus acciones. Por ejemplo, cambia:
<accion nombre="borrar" modo="detalle" confirmar="true"
    clase="com.miempresa.miaplicacion.acciones.MiBorrar"
    imagen="delete.gif"
    atajo-de-teclado="Control D"/>
Por esto:
<accion nombre="borrar" mode="detalle" confirmar="true"
    clase="com.miempresa.miaplicacion.acciones.MiBorrar"
    icono="delete"
    atajo-de-teclado="Control D"/>
Para ver todos los iconos disponibles visita Material Design Icons.
Por otra parte, si prefieres seguir con los viejos iconos de toda la vida, simplemente añade la siguiente línea en xava.properties:
useIconsInsteadOfImages=false
De esta manera todas las acciones, incluyendo las estándar, usarán las viejas imágenes en color.

Para migrar de OpenXava 5.3.1 a OpenXava 5.3.2

No hay consideraciones.

Para migrar de OpenXava 5.3 a OpenXava 5.3.1

El jar de HSQLDB se ha movido desde OpenXavaTest a OpenXava

Si referencias a este jar tendrás que cambiar la ruta. Por ejemplo, si utilizas HSQLDB en alguno de tus proyectos, deberías cambiar en la tarea Ant actualizarEsquema de build.xml esto:
<property name="schema.path" value="../OpenXavaTest/lib/hsqldb.jar"/>
Por esto:
<property name="schema.path" value="../OpenXava/lib/hsqldb.jar"/>

Para migrar de OpenXava 5.2.1 a OpenXava 5.3

Hibernate actualizado a 4.3

Si usas la API de JPA o haces un uso básico de la API de Hibernate no tendrás que cambiar nada. Ahora bien, si usas características avanzadas de Hibernate seguramente esta actualización te afecte.
Por ejemplo, si tienes tu propios tipos de Hibernate (UserType) has de cambiar en tu definición de tipo lo siguiente:
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
Por:
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor sessionImplementor, Object owner) throws HibernateException, SQLException {
Y esto:
public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException {
Por:
public void nullSafeSet(PreparedStatement ps, Object value, int index, SessionImplementor sessionImplementor) throws HibernateException, SQLException {
Por supuesto, si llamas a estos métodos debes de adaptar la llamada. Por ejemplo, un código como este:
((UserType) hibernateType).nullSafeSet(ps, o, 1);
Se quedaría:
((UserType) hibernateType).nullSafeSet(ps, o, 1, null);
Fíjate en que enviar un nulo para el nuevo parámetro es suficiente.
Además, en lugar de Hibernate.INTEGER has de usar IntegerType.INSTANCE.
La forma de registrar los eventos ha cambiado, esto te afecta sólo si usas componentes XML con el API de JPA, en cuyo caso has de quitar el registro de eventos de tu persistence.xml, como sigue:
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
 
    <properties>
        <property name="hibernate.ejb.cfgfile" value="/hibernate-jpa.cfg.xml"/>
        <!-- ELIMINA LAS SIGUIENTES LÍNEAS
        <property name="hibernate.ejb.event.pre-insert" value="org.openxava.hibernate.impl.CalculatorsListener, org.openxava.hibernate.impl.ReferenceConverterToDBListener, org.openxava.hibernate.impl.DefaultValueCalculatorsListener"/>
        <property name="hibernate.ejb.event.pre-update" value="org.openxava.hibernate.impl.CalculatorsListener, org.openxava.hibernate.impl.ReferenceConverterToDBListener"/>
        <property name="hibernate.ejb.event.pre-delete" value="org.openxava.hibernate.impl.CalculatorsListener"/>
        <property name="hibernate.ejb.event.post-load" value="org.openxava.hibernate.impl.CalculatorsListener"/>
        -->
    </properties>
</persistence-unit>
También si usas componentes XML ya no puedes tener una referencia usada como clave si el valor no existe en la tabla referenciada. Este caso ya no está permitido por Hibernate. Este caso nunca ha estado permitido en JPA. Deberías de pensar en una forma diferente de resolver el problema, como añadiendo una clave autogenerada o creando el registro en la tabla referenciada.
Con Hibernate 4.3 la forma por defecto de liberar una conexión ha cambiado, por lo que te podrías encontrar un "Could not open connection error". Para evitarlo añade la siguiente línea a tu persistence.xml:
<persistence-unit name="default">
    ...
    <properties>
        ...
        <!-- Añade la siguiente línea -->
        <property name="hibernate.connection.release_mode" value="after_transaction"/>
 
    </properties>
 
</persistence-unit>

Hibernate Validator 3 quitado de la distribución

Hasta ahora hemos incluido ambos, el antiguo Hibernate Validator 3 y la última versión de Hibernate Validator, en OpenXava para conseguir la máxima compatibilidad del código antiguo. Por desgracia, Hibernate 4.3 no soporta Hibernate Validator 3, por eso hemos tenido que quitarlo de OpenXava.
Si simplemente usas anotaciones de validación como @Max, @Length, @Size, etc. es suficiente con cambiar los imports, cambia:
import org.hibernate.validator.*;
Por:
import javax.validation.constraints.*;
import org.hibernate.validator.constraints.*;
En el caso de @Digits aparte de cambiar los susodichos imports tienes que cambiar los nombres de los parámetros, cambiando esto:
@Digits(integerDigits=10, fractionalDigits=6)
Por esto:
@Digits(integer=10, fraction=6)
Ya no puedes usar InvalidStateException de Hibernate Validator 3. Por lo tanto, si la usas para lanzar un error de validación desde tu entidad u acción tendrás que cambiarla por otra excepción. Por ejemplo, un código como el siguiente:
@PreRemove
public void validarAlBorrar() {
    if (numero == 1) {
        throw new InvalidStateException(
            new InvalidValue [] {
                new InvalidValue(
                    "uno_no_se_puede_borrar", getClass(), "numero",
                    getNumero(), this)
            }
        );
    }
}
Ahora podría escribirse de esta manera:
@PreRemove
public void validarAlBorrar() {
    if (numero == 1) {
        throw new javax.validation.ValidationException("uno_no_se_puede_borrar");
    }
}
Si has definido tu propio validador con el Hibernate Validator antiguo deberías reescribirlo usando el estándar Bean Validation. No te preocupes, la conversión es muy sencilla. En tu anotación cambia @ValidatorClass por @Constraint y añade groups() y payload(), así:
@Constraint(validatedBy = MyValidator.class) // En lugar de @ValidatorClass(PropertyValidatorValidator.class)
public @interface MyAnnotation {
 
    ...
 
    // Añade el siguiente código
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
 
}
Y en tu clase validador, cambia esto:
public class RequiredValidator implements Validator<Required> {
Por:
public class RequiredValidator implements ConstraintValidator<Required, Object> {
Y esto:
public boolean isValid(Object value) {
Por:
public boolean isValid(Object value, ConstraintValidatorContext context) {
Puedes dejar el resto del código como está.

@Required, @PropertyValidator y @EntityValidator son restricciones de Bean Validation

Antes eran restricciones de Hibernate Validator 3. Si haces tu propio commit y tratas de capturar la excepción de validación has de cambiar la excepción a atrapar. Si tienes un código como este:
try {
    XPersistence.commit();
}
catch (RollbackException ex) {
    if (ex.getCause() instanceof InvalidStateException) {
        InvalidStateException iex = (InvalidStateException) ex.getCause();
        int cantidadValoresInvalidos = iex.getInvalidValues().length;
        String propiedad = iex.getInvalidValues()[0].getPropertyName();
        String mensaje = iex.getInvalidValues()[0].getMessage();
        ...
    }
}
Deberías escribirlo de esta manera:
try {
    XPersistence.commit();
}
catch (RollbackException ex) {
    if (ex.getCause() instanceof ConstraintViolationException) {
        ConstraintViolationException cex = (ConstraintViolationException) ex.getCause();
        int cantidadValoresValidos = cex.getConstraintViolations().size();
        ConstraintViolation v = cex.getConstraintViolations().iterator().next();
        String propiedad = v.getPropertyPath().toString());
        String mensaje = v.getMessage());
        ...
    }
}

Prefijo para JNDI en Tomcats antiguos

Hibernate 4.3 usa una forma diferente de buscar los recursos JNDI que funciona bien con Tomcat 7.0.27 (y superior) y Tomcat 6.0.36 (y superior) pero falla con versiones anteriores. Esto no es un bug de Hibernate sino un bug del Tomcat. Por suerte, hay un truco para hacer que el nuevo Hibernate funcione incluso con las versiones antiguas de Tomcat, simplemente añade un // al nombre JNDI. Es decir, si estás usando una versión de Tomcat anterior a 7.0.27 o 6.0.36 cambia en tu persistence.xml esto:
<non-jta-data-source>java:comp/env/jdbc/TuAplicacionDS</non-jta-data-source>
Por esto:
<non-jta-data-source>java://comp/env/jdbc/TuAplicacionDS</non-jta-data-source>
Y en hibernate.cfg.xml cambia esto:
<property name="hibernate.connection.datasource">java:comp/env/jdbc/TuAplicacionDS</property>
Por esto otro:
<property name="hibernate.connection.datasource">java://comp/env/jdbc/TuAplicacionDS</property>
Fíjate en // antes de comp. Si usas nombres JNDI en otras partes de tu aplicación también tendrías que cambiarlos. Lo bueno es que las nuevas versiones de Tomcat también funcionan de esta forma, por tanto si usas siempre esta notación tu aplicación funcionará en cualquier Tomcat.

Actualización de librerias EL para Tomcat 6

Si usas Tomcat 6 copia el-api.jar y jasper-el.jar de la carpeta lib del Tomcat incluido en OpenXava (o cualquier Tomcat 7) a la carpeta lib de tu Tomcat 6. Esto es requerido por última versión de Hibernate Validator.

Librería Automated Business Logic (ABL) quitada de la distribución

Por desgracia, ABL no soporta Hibernate 4.3. Además, ABL ha sido descontinuada desde 2012, por tanto tampoco soportará Hibernate 4.3 en el futuro. Por lo tanto, no tenemos otra opción que quitar ABL de la distribución de OpenXava. Por suerte, mover la lógica en las anotaciones ABL a código Java es fácil. Por ejemplo, si tienes una clase de lógica ABL como esta:
public class PedidoLogic {
 
    @Formula("precioProducto * cantidad")
    public void deriveImporte() { }
 
}
Borra la clase de arriba y mueve el cálculo en la anotación @Formula a un método @PrePersist y @PreUpdate en la entidad. Así:
@Entity
public class Pedido {
 
    ...
 
    @PrePersist @PreUpdate
    private void deriveImporte() {
        importe = new BigDecimal(cantidad).multiply(precioProducto);
    }
}
Además, has de eliminar la siguiente entrada de tu persistence.xml:
<property name="hibernate.current_session_context_class"
    value="com.autobizlogic.abl.session.LogicThreadLocalSessionContext"/>

schema.path necesario en tarea ant generarEsquema

Esto afecta a generarEsquema no a actualizarEsquema. Si tienes una tarea generarEsquema en tu build.xml, añade schema.path, como sigue:
<!-- Genera el esquema desde cero. Lo muestra en consola, pero no lo ejecuta -->
<target name="generarSchema">
 
    <ant antfile="../OpenXava/build.xml" target="generateSchemaJPA">
        <property name="persistence.unit" value="junit"/>
        <!-- AÑADE LA SIGUIENTE LÍNEA PARA v5.3 -->
        <property name="schema.path" value="../OpenXavaTest/lib/hsqldb.jar"/>
    </ant>
 
</target>

Para migrar de OpenXava 5.2 a OpenXava 5.2.1

Entidad obtenida de la vista tiene nulos para referencias inexistentes

Hasta v5.2 todas las referencias de una entidad obtenida vía getView().getEntity() tenían valor, incluso si las referencias no existían. Esto producía un error muy feo porque JPA trataba de grabar los objetos transitorios como referencias. A partir de v5.2.1, las referencias vacías son nulo, esto es más natural (funciona como cuando obtenemos los objetos de la base de datos) y resuelve el susodicho error.
Si tienes código que confía en este comportamiento tienes que cambiarlo. Es decir, has de hacer cambios como este:
Factura factura = (Factura) getView().getEntity();
if (factura.getCliente().getCodigo() == 0) { // En v5.2 si cliente está vacío se devuelve un cliente vacío
Por:
Factura factura = (Factura) getView().getEntity();
if (factura.getCliente() == null) { // En v5.2.1 si cliente está vacío se devuelve nulo

Para migrar de OpenXava 5.1.x a OpenXava 5.2

HtmlUnit actualizado a 2.15

Si usas HtmlUnit directamente en tus pruebas jUnit por medio de getHtmlPage() o getWebClient() deberías adaptar tu código a la nueva API de HtmlUnit. Por ejemplo, deberías cambiar:
getWebClient().setCssEnabled(true);
Por:
getWebClient().getOptions().setCssEnabled(true);
Y:
HtmlElement consola = getHtmlPage().getElementById("xava_console");
Por:
HtmlElement consola = getHtmlPage().getHtmlElementById("xava_console");
Y muchas más cosas. Por desgracia, el equipo de HtmlUnit refactoriza su librería en cada nueva versión menor, por tanto HtmlUnit nunca es compatible hacia atrás.

Para migrar de OpenXava 5.0.x a OpenXava 5.1

@DefaultValueCalculator dependiente de otras propiedades cambia su comportamiento

Si tienes un calculador por defecto como este:
@DefaultValueCalculator(
    value=CalculadorPrecioUnitario.class,
    properties=@PropertyValue(
        name="numeroProducto",
        from="producto.numero")
)
private BigDecimal precioUnitario;
Con versiones anteriores a 5.1 cuando producto.numero cambia precioUnitario se recalcula solo si no tiene valor todavía. Desde la versión 5.1 precioUnitario se recalcula siempre que producto.numero cambia.
Este nuevo comportamiento es más natural, por tanto si no cambias nada tus usuarios tendrán una aplicación que funciona mejor. De todas formas, puede ser que quieras que el valor se recalcule sólo la primera vez, como antes. En ese caso deberías reescribir tu lógica usando @OnChage, es decir, deberías cambiar el código de arriba por este:
@OnChange(RecalcularPreciOUnitarioAlCambiarProducto.class)
private Producto producto;
 
private BigDecimal precioUnitario;

Para migrar de OpenXava 4.9.1 a OpenXava 5.0

La identifación de usuarios afecta a tus pruebas jUnit

Ahora es obligatorio que el usuario se identifique antes de ejecutar un módulo, por tanto tus actuales pruebas jUnit fallarán. Para resolver esto desactiva el mecanismo de identificación de usuarios añadiendo las siguientes entradas al archivo naviox.properties en properties folder:
autologinUser=admin
autologinPassword=admin
De esta manera tus pruebas funcionarán bien sin necesidad de recodificarlas.
Otra opción es dejar el mecanismo de identificación activo y añadir la lógica de identificación en tu código de pruebas:
public void testMiPrueba() throws Exception {
    login("admin", "admin");
    ...
}

Ejecutar los módulos en solitario ya no está disponible por defecto

Cuando vas a /MiAplicacion/modules/MiModule con tu navegador, el modulo se muestra con menus e identificación de usuarios incluidos. Esto no es un problema en absoluto, porque los menús son muy ligeros y la identificación de usuario puede desactivarse con autologinUser y autologinPassword en naviox.properties. Además, dentro de Liferay los módulos funcionan como siempre.
Pero si por alguna razón prefieres trabajar de la forma antigua puedes desactivar la identificación de usuarios y los menús y usar el viejo estilo visual para tus módulos en OpenXava 5. Para hacerlo edita el archivo web.xml del proyecto OpenXava y quita:
<filter>
    <filter-name>naviox</filter-name>
    <filter-class>com.openxava.naviox.web.NaviOXFilter</filter-class>
</filter>
 
<filter-mapping>
    <filter-name>naviox</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>
 
<filter-mapping>
    <filter-name>naviox</filter-name>
    <servlet-name>naviox</servlet-name>
</filter-mapping>
 
<filter-mapping>
    <filter-name>naviox</filter-name>
    <servlet-name>module</servlet-name>
</filter-mapping>
Además cambia:
<servlet>
    <servlet-name>naviox</servlet-name>
    <servlet-class>com.openxava.naviox.web.NaviOXServlet</servlet-class>
</servlet>
Por:
<servlet>
    <servlet-name>modules</servlet-name>
    <servlet-class>org.openxava.web.servlets.ModuleServlet</servlet-class>
</servlet>
Y cambia:
<servlet-mapping>
    <servlet-name>naviox</servlet-name>
    <url-pattern>/modules/*</url-pattern>
</servlet-mapping>
Por:
<servlet-mapping>
    <servlet-name>modules</servlet-name>
    <url-pattern>/modules/*</url-pattern>
</servlet-mapping>
Finalmente quita:
<servlet-mapping>
    <servlet-name>naviox</servlet-name>
    <url-pattern>/m/*</url-pattern>
</servlet-mapping>
Con estos cambios en OpenXava/web.xml has eliminado los menús y la identificación de usuarios. Tienes que ejecutar la tarea ant actualizarOX para actualizar el web.xml en tu proyecto.
Para usar el estilo visual de OpenXava 4 añade las siguientes entradas a xava.properties de tu proyecto:
styleClass=org.openxava.web.style.Liferay51Style
styleCSS=liferay51/css/everything_unpacked.css

El estilo nativo de iPad no se usa por defecto

Cuando accedes a una aplicación OpenXava 5 desde un iPad el estilo es el mismo que en un navegador de escritorio, el estilo iPad no se muestra por defecto. Esto es así porque el estilo iPad sólo funciona en módulos en solitario, que OpenXava 5 no usa por defecto. Si quieres usar el estilo nativo de iPad sigue las instrucciones de arriba en la sección Ejecutar los módulos en solitario ya no está disponible por defecto para activar lo módulos en solitario.
Sobre el soporte de iPad y tabletas vamos a tener un único estilo que funcione bien para escritorio y tabletas, un estilo adaptable (responsive).

Las clases transitorias requieren un declaración expicita de módulo

Por ejemplo, si tienes una clase transitoria llamada FiltroPorMes con un controlador llamado FiltroPorMes y pruebas la URL /MiAplicacion/modules/FiltroPorMes, no funcionará hasta que declares el módulo en aplicacion.xml como sigue:
<modulo nombre="FiltroPorMes">
    <modelo nombre="FiltroPorMes"/>
    <controlador nombre="FiltroPorMes"/>
</modulo>
De todas formas, siempre ha sido necesario declarar los módulos para las clases transitorias si queriamos generar portlets, por lo tanto si trabajas con portales ya tendrás los módulos definidos.

Nivel de log FINEST genera un montón de traza

Hasta ahora el nivel de log FINEST producía poca traza, pero a partir de v5.0 OpenXava genera abundante traza con FINEST. Por tanto has de editar tu archivo xava.properties y cambiar:
javaLoggingLevel=FINEST
Por:
javaLoggingLevel=FINE
Si quieres mantener una cantidad de traza moderada.
Hasta v4.9.1 los proyectos OpenXava creados con OpenXavaPlantilla tenían FINEST configurado por defecto, a partir de v5.0 tienen FINE.

Eliminada clase Objects de org.openxava.util

Esta clase entra en conflicto con la clase java.util.Objects de Java 7. En lugar de calificar la clase en todos sitios preferimos renombrarla a XObjects. En tu código has de reemplazar Objects por XObjects, como sigue:
Objects.execute(miObjeto, "hacerAlgo");
Ahora tienes que escribir en su lugar:
XObjects.execute(miObjeto, "hacerAlgo");

AccessTracking quitado de la distribución

Puedes continuar usando AccessTracking sin ningún problema, simplemente ejecuta la tarea ant updateOX de AccessTracking después de ejecutar OpenXava.

La URL usada por ModuleTestBase incluye un parámetro por defecto

Esto sólo te afecta si sobrescribes getModuleURL() para añadir parámetros. En este caso simplemente cambia ? por &:
public class MiModuloTest extends ModuleTestBase {
 
    ...
 
    @Override
    protected String getModuleURL() {
        // return super.getModuleURL() + "?miParametro=5"; // Con ? en v4.x.x
        return super.getModuleURL() + "&miParametro=5"; // Con & en v5.0
    }
}

@Digits anula la escala por defecto

Cuando @Digits se especifica la escala por defecto se ignora, incluso si la fracción no se especifica. Es decir, si escribes:
@Digits(integer=10)
private BigDecimal importe;
Con v4.x tiene 2 cifras decimales porque la escala por defecto para BigDecimal es 2. Sin embargo, a partir de v5.0 tiene 0 cifras decimales, porque no especificar fracción es lo mismo que poner fraction=0. Esto te permite tener números BigDecimal con 0 para la parte decimal, pero podría hacer que algunas de tus actuales propiedes numéricas dejen de usar 2 dígitos para la fracción. Para arreglarlo simplemente especifíca la fracción explicitamente, así:
@Digits(integer=10, fraction=2)
private BigDecimal importe;

Formateo de BigDecimal arreglado (para pruebas jUnit)

La escala definida en default-size.xml, en @Column y @Digits se ignoraba al formatear. Lo hemos arreglado. Sí, el formateo de los número funciona mejor, pero tienes que adaptar tus pruebas. Por ejemplo, si usas BigDecimal sin anotaciones deberías cambiar:
assertValue("miNumeroBigDecimal", "20");
por esto:
assertValue("miNumeroBigDecimal", "20.00");

Para migrar de OpenXava 4.9 a OpenXava 4.9.1

Modificador de acceso del método getFrame() cambiado

El modificador de acceso del método getFrame() de org.openxava.web.style.Style fue cambiado de protected a public. Las clases que sobrescriben el método getFrame() requieren que se les cambien el modificador de acceso de protected a public.

Para migrar de OpenXava 4.8.1 a OpenXava 4.9

Cabeceras de informes PDF pueden ocupar varias líneas

Esto no afecta al codigo de tu aplicación en absoluto. Sin embargo, si verificas el contenido del PDF en tus pruebas automáticas quizás necesites hacer algunos ajustes. Por ejemplo, el siguiente código fallaría si la cabecera del informe ahora usará 2 líneas en vez de 1.:
assertPopupPDFLinesCount(5); // Quizás ahora hay 6 líneas, porque la cabecera usa 2 líneas

Controlador CustomReport renombrado a MyReport

Es poco probable que tengas que cambiar tu código, porque este controlador es para uso interno del diálogo 'Mis informes' y sólo está disponible desde OpenXava 4.6. Sin embargo, si has usado acciones del controlador CustomReport en tus pruebas jUnit has de renombrarlas a MyReport.

Para migrar de OpenXava 4.8 a OpenXava 4.8.1

Ocultar un miembro cuyo nombre es el mismo que la sección que lo contiene

Hemos arreglado View.setHidden() para que funcione con secciones también, ya funcionaba con grupos pero no con secciones. Por lo tanto, si tienes una vista como esta:
@View(members=
  ...
  "observaciones { consejo, atajo; observaciones }"
  ...
)
Donde la propiedad observaciones está dentro de una sección llamada observaciones. Hasta ahora si escribías esto:
getView().setHidden("observaciones", true);
Ocultabas la propiedad observaciones, sin embargo desde OpenXava 4.8.1 ocultarás la sección observaciones. En este caso, si aún quieres ocultar la propiedad en lugar de la sección deberías renombrar la sección, como sigue:
@View(members=
   ...
   "comentarios { consejo, atajo; observaciones }"
   ...
)

Para migrar de OpenXava 4.7.1 a OpenXava 4.8

Sin consideraciones.

Para migrar de OpenXava 4.7 a OpenXava 4.7.1

La acción Gallery.return ha sido renombrada como Gallery.close

Esto es porque ahora el editor Gallery usa un diálogo en vez de una vista plana. Además, el controlador para Gallery de solo lectura es Close en vez de Return. Es poco probable que tengas que tocar tu código por estos cambios. Sin embargo, si la has usado en pruebas jUnit tendrás que renombrarla.

Para migrar de OpenXava 4.6.1 a OpenXava 4.7

La acción ExtendedPrint.customReport ha sido renombrada como ExtendedPrint.myReports

Es poco probable que tengas que tocar tu código por este cambio, porque esta es una acción de Typical (por tanto siempre presente) y disponible sólo desde OpenXava 4.6. Sin embargo, si la has usado en pruebas jUnit, @Action o IChainAction, tendrás que renombrarla.

El método getSelected() de Tab y TabBaseAction obsoleto, ahora usamos getSelectedKeys()

El método getSelected() incluido en Tab y TabBaseAction ha sido marcado como obsoleto (deprecated) en sustitución tenemos disponible el método getSelectedKeys() que nos devuelve las claves (Map) de los elementos que se hayan seleccionado.
En la mayoría de casos getSelected() devolverá correctamente las filas que se han seleccionado, pero en el caso de tener alguna fila seleccionada fuera del rango de páginas cargadas no lo hará. Esto ocurrirá por ejemplo si seleccionamos una fila y después ordenamos por algún campo y esta fila queda fuera del rango de páginas cargadas, getSelected() no devolverá esta fila getSelectedKeys() sí.
En nuestro código cambiaremos:
int[] selected = tab.getSelected();
for (int i = 0; i < selected.length; i++){
     Map clave = (Map) tab.getTableModel().getObjectAt(selected[i]);
     ....
}
por
Map[] selected = tab.getSelectedKeys();
for (int i = 0; i < selected.length; i++){
     Map clave = selected[i];
     ....
}

Suprimido método deselectVisualizedRows de la clase Tab


Para migrar de OpenXava 4.6 a OpenXava 4.6.1

Mensajes en archivos i18n sin argumentos ahora son formateados de manera estándar

Esto es realmente el arreglo de un fallo, pero puede afectar tus mensajes i18n si estos contienen apóstrofes, por tanto has de cambiar:
mi_mensaje=T'ha dit que no
por
mi_mensaje=T''ha dit que no
Fíjate como hay que cambiar ' por ''.

Para migrar de OpenXava 4.5.1 a OpenXava 4.6

Sin consideraciones.

Para migrar de OpenXava 4.5 a OpenXava 4.5.1

Los editores personalizados han de especificar el atributo tabindex

Para estar en el orden correcto de tabulación los editores tienen que especificar tabindex="1" en su HTML, así:
<input id="<%=propertyKey%>"
    name="<%=propertyKey%>" class="<%=style.getEditor()%> <%=numericClass%>"
    type="<%=inputType%>"
    tabindex="1" <!-- Ahora hay que poner esto -->
    ...
/>

Para migrar de OpenXava 4.4.x a OpenXava 4.5

Select íntegro en baseCondition de @Tab ahora tiene que usar sintaxis JPQL y no SQL

A partir de v4.5 OpenXava usa JPA para obtener datos tabulares, antes usaba SQL. Esto significa que cuando uses baseCondition para escribir un select completo has de utilizar la sintaxis JPQL, SQL ya no se soporta.
Es decir, si tienes un select como este:
baseCondition =
    "select CODIGO, DESCRIPCION, FAMILIA.DESCRIPCION " +
    "from   XAVATEST.SUBFAMILIA, XAVATEST.FAMILIA " +
    "where  SUBFAMILIA.FAMILIA = FAMILIA.CODIGO"
Lo has de reescribir de esta forma:
baseCondition =
    "select e.codigo, e.descripcion, f.descripcion " +
    "from Subfamilia e, Familia f " +
    "where e.codigoFamilia = f.codigo"
La sintaxis de JPQL y SQL son muy parecidas, normalmente no es necesario hacer grandes cambios más allá de cambiar los nombres de tablas y columnas por nombres de propiedades y tablas. Has de usar e como alias para la entidad principal.

El atributo condition de @DescriptionsList ahora usa sintaxis JPQL y no SQL

A partir de v4.5 OpenXava usa JPA para obtener datos de los combos, por tanto has de usar sintaxis JPQL en condition. Si no usas condiciones demasiado complicadas y usas ${nombrePropiedad} en vez de nombre de columna, seguramente no tendrás que hacer ningún cambio. Sin embargo, puede ser que necesitas hacer algún cambio, especialmente si usas nombres de columna. Por ejemplo, el siguiente código ya no funciona:
@DescriptionsList(
    // No funciona porque IDCOSA es un nombre de columna, por eso JPA no lo reconoce
    condition="${cosa.codigo} = (SELECT IDCOSA FROM ${Cosa} WHERE nombre = 'COCHE')"
)
La solución es usar nombres de propiedades en vez de nombres de columnas, en este caso cambiando IDCOSA por codigo es suficiente para resolver el problema:
@DescriptionsList(
    // Funciona porque usamos el nombre de propiedad, codigo, en vez de IDCOSA
    condition="${cosa.codigo} = (SELECT codigo FROM ${Cosa} WHERE nombre = 'COCHE')"
)
Otra opción es escribir la sentencia completa en puro JPQL, dado que los ${} ya no son necesarios, como sigue:
@DescriptionsList(
    // Podemos usar JPQL puro sin ${nombrePropiedad}
    condition="e.cosa.codigo = (SELECT c.codigo FROM Cosa c WHERE c.nombre = 'COCHE')"
)
Si usas JPQL has de usar e como alias para la entidad principal.

@OnSelectElementAction no refresca por defecto su colección

Este nuevo comportamiento produce un rendimiento mucho mayor en la mayoría de los casos, especialmente cuando trabajas con una colección muy grande y seleccionas elementos que no cambian los datos de la colección. Sin embargo, si tienes un caso donde tu @OnSelectElementAction cambia el contenido de la colección has de refrescar las colecciones explicitamente, como sigue:
public class MiOnSelectElementAction extends OnSelectElementBaseAction {
 
    public void execute() throws Exception {
        hacerAlgoQueModificaLaColeccion();
        getView().refreshCollections(); // A partir de v4.5 has de añadir esta linea
    }
 
}

Para migrar de OpenXava 4.3.x a OpenXava 4.4

HtmlUnit actualizado de 2.5 a 2.9

HtmlUnit es la librería que se usa para simular un navegador desde las pruebas jUnit. Se ha actualizado a la versión 2.9. HtmlUnit ha renombrado y eliminado algunos métodos y clases, de hecho la gente de HtmlUnit está siempre refactorizando su librería (refactorizar es bueno para las aplicaciones pero no lo es tanto para una libreria). Lo más probable es que no tengas que cambiar nada en tus pruebas jUnit porque ModuleTestBase oculta HtmlUnit, sin embargo si usas la API de HtmlUnit directamente, usando getHtmlPage() de ModuleTestBase por ejemplo, quizás tengas que adaptar algunas llamadas a métodos.

Para migrar de OpenXava 4.2.x a OpenXava 4.3

Sin consideraciones.

Para migrar de OpenXava 4.1.x a OpenXava 4.2

Sin consideraciones.

Para migrar de OpenXava 4.0.1 a OpenXava 4.1

Nueva acción en lista y colecciones (para pruebas junit)

La lista y las colecciones tienen una nueva acción disponible (List.sumColumn), por lo tanto si compruebas todas las acciones presentes en tu prueba junit, tendrás que modificarlo para tener en cuenta la nueva acción "List.sumColumn":
private String [] accionesLista = {
  "Mode.detailAndFirst",
  "Mode.split",
  "List.filter",
  "List.customize",
  "List.orderBy",
  "List.viewDetail",
  "List.hideRows",
  "List.sumColumn" // AÑADE ESTA ENTRADA
};
assertActions(accionesLista);

Para migrar de OpenXava 4.0 a OpenXava 4.0.1

Ya no hay conversor por defecto para boolean

A partir de ahora no hay conversor por defecto denido en default-converters.xml para java.lang.Boolean y boolean. En realidad, esto no produce ningún problema de incompatibilidad en las aplicaciones JPA, ya que en estas aplicaciones el motor JPA hace la coversión el mismo. Sin embargo, si tienes una aplicación XML antigua, sólo has de regenerar el código y todo funcionará perfectamente, porque la mayoría de las bases de datos hace un buen trabajo al traducir de boolean a numérico automáticamente. De todas formas, puedes configurar tu aplicación para que funcione como antes, simplemente añade las siguiente líneas al archivo conversores.xml en la carpeta xava de tu aplicación:
<para-tipo tipo="boolean"
  clase-conversor="org.openxava.converters.Boolean01Converter"
  tipo-cmp="java.lang.Integer"/>
 
<para-tipo tipo="java.lang.Boolean"
  clase-conversor="org.openxava.converters.Boolean01Converter"
  tipo-cmp="java.lang.Integer"/>
Recuerda, añadir estás líneas no suele ser necesario, regenerar código sin más debería ser suficiente. Y si tu aplicación es JPA (el caso más normal) no necesitas hacer nada.

Para migrar de OpenXava 4m6 a OpenXava 4.0

Sin consideraciones.

Para migrar de OpenXava 4m5 a OpenXava 4m6

Hibernate actualizado a Hibernate 3.6

En OpenXava 4m6 Hibernate ha sido actualizado a Hibernate 3.6 para poder soportar JPA 2.0. La mayoría del código funciona sin hacer ninguna modificación. Sin embargo, hay algunos detalles que quizás tengas que modificar en tu código. Abajo encontrarás alguno de estos detalles.
Adicionalmente, es muy recomendable que repliegues (desinstales) tu vieja aplicación del servidor de aplicaciones, y la vuelvas a desplegar. Es decir, borra la vieja aplicación de la carpeta webapps del Tomcat, antes de desplegar una nueva versión de ésta basada en OX4m6, así nos aseguramos de que los viejos jars de JPA e Hibernate se han borrado. Borra también las carpetas .dist de tu workspace o workspace.dist.

Referencias @ManyToOne inexistentes usadas como @Id ya no están soportadas (Hibernate 3.6)

Hibernate 3.6 no soporta referencias @ManyToOne inexistentes usada como @Id. Es decir, si tienes una entidad con las siguientes claves:
public class Albaran {
 
  @Id @Column(length=5)
  private int numero;
 
  @Id @ManyToOne(fetch=FetchType.LAZY)
  private TipoAlbaran tipo;  // El tipo ha de existir en la base de datos
  ...
}
En este caso el TipoAlbaran referenciado tiene que existir siempre en la base de datos.
Realmente, este es un caso muy raro que sólo te encontrarás cuando trabajes contra bases de datos legadas diseñadas por programadores la era pre-RDBMS (como los programadores RPG). Ellos a veces usan claves que incluyen referencias a otras tablas, y cuando esas referencias no existen ponen ceros en los campos. Si te encuentras con este caso puedes resolverlo de alguna de las siguientes maneras:
  • Crea una fila en la tabla referenciada con 0 como clave.
  • Usa una propiedad plana en vez de una referencia. En este caso puedes usar un editor especial para la propiedad.
  • Permite nulos para la columna usada como pseudo-clave-foranea y cambia todos los ceros por nulos en esa columna.

Para poder asignar una entidad ya existente ésta ha de ser 'manejada' (Hibernate 3.6)

Es decir, en las versiones previas de Hibernate podías escribir:
Albaran albaran = new Albaran();
TipoAlbaran tipoAlbaran = new TipoAlbaran(); // Creamos un nuevo TipoAlbaran
                                             // en lugar de buscarlo
tipoAlbaran.setNumero(66); // El TipoAlbaran 66 ya existe en la base de datos
albaran.setTipo(tipoAlbaran);
...
XPersistence.getManager().persist(albaran);
Pero, esto no funciona con Hibernate 3.6, en su lugar has de escribirlo lo siguiente:
Albaran albaran = new Albaran();
TipoAlbaran tipoAlbaran = XPersistence.getManager()
  .find(TipoAlbaran.class, 66); // Lo buscamos
albaran.setTipo(tipoAlbaran);
XPersistence.getManager().persist(albaran);

Entidad con solo una referencia @ManyToOne como clave (Hibernate 3.6)

Con versiones anteriores de Hibernate podías escribir el siguiente código en tu entidad:
@Entity
@IdClass(PersonaContactoClienteKey.class)
public class PersonaContactoCliente {
 
  @Id @ManyToOne(fetch=FetchType.LAZY)
  private Cliente cliente;
 
  // No más campos @Id
 
  ...
 
}
Y la referencia de esta forma:
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="CUSTOMERCONTACT") // Sin el atributo referencedColumnName
private PersonaContactoCliente personaContactoCliente;
Y esto funcionaba. Sin embargo, con Hibernate 3.6 esto no funciona. Afortunadamente, hay una forma de conseguir el mismo efecto. Escribe tu entidad de la siguiente forma:
@Entity // @IdClass ya no se usa
public class PersonaContactoCliente
  implements java.io.Serializable { // Tiene que implementar Serializable
 
  @Id @ManyToOne(fetch=FetchType.LAZY)
  private Cliente cliente;
 
  // No más campos @Id
 
  ...
 
}
Y la referencia de esta forma:
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
  @JoinColumn(name="CUSTOMERCONTACT",
    referencedColumnName="CUSTOMER_NUMBER") // referencedColumnName es obligatorio
})
private PersonaContactoCliente personaContactoCliente;

Type de Hibernate CharBooleanType no funciona (Hibernate 3.6)

CharBooleanType (y algunos otros types de Hibernate) ha sido marcado como obsoleto (deprecated), es más, no funcioa bien en Hibernate 3.6. Si tienes algún type que extienda de CharBooleanType, tienes que reescribirlo para extender de AbstractSingleColumnStandardBasicType. Mira SiNoType en el paquete org.openxava.types.

Entidades con @DiscriminatorColumn arroja errores (Hibernate 3.6)

Las entidades que contengan discriminador que sea parte de la clave, arrojarán error de campo duplicado. Suponga que tiene una entidad anotada de la siguiente manera:
@Entity
@Table(name = "`TABLAS`")
@DiscriminatorColumn(name="ID",
        discriminatorType=DiscriminatorType.STRING,
        length=20)
 
Hibernate 3.4 correrá sin problemas, pero la versión 3.6 (y me parece que la 3.5 también) les arrojará el error de campo duplicado. Para corregir esto debe utilizar una anotación dependiente de Hibernate @DiscriminatorOptions de la siguiente forma:
@Entity
@Table(name = "`TABLES`")
@DiscriminatorColumn(name="ID",
        discriminatorType=DiscriminatorType.STRING,
        length=20)
@DiscriminatorOptions(insert = false) // Anotacion dependiente de Hibernate
 
Y debe funcionar correctamente.

Método getProperty() renombrado en ModuleTestBase

El método getProperty() de ModuleTestBase ha sido renombrado como getXavaJUnitProperty(). Por tanto, si lo usas en tu prueba has de renombrar la llamada al método, como sigue:
String host = getProperty("host"); // Hasta v4m5
// Tiene que cambiarse por
String host = getXavaJUnitProperty("host"); // A partir de v4m6
Este cambio fue necesario para permitir usar Groovy al escribir pruebas JUnit.

Para migrar de OpenXava 4m4 a OpenXava 4m5

El controlador Navigation no se añade automáticamente

Hasta ahora el controlador Navigation (con las acciones anterior - inicio - siguiente en modo detalle) era añadido automáticamente a todos los módulos con detalle y lista. A partir de ahora, este controlador ya no se añadirá implícitamente. Esto no es un problema ya que Typical lo exteniende, pero si tienes un módulo con detalle - lista sin controlador Typical, en ese caso has de añadir Navigation explícitamente:
<modulo nombre="CambiarPrecioProducto">
  <modelo nombre="Producto"/>
  <controlador nombre="Navigation"/>  <!-- Has de añadir esto -->
  <controlador nombre="CambiarPrecioProducto"/>
</modulo>

Nuevo modo split (partido) - Cambios en jUnit

Además de detalle y lista, ahora tenemos un nuevo modo, split (partido), que permite mostrar la lista y el detalle al mismo tiempo. Esta funcionalidad no produce ninguna incompatibilidad a nivel de aplicación, pero si usas assertActions() en tus pruebas puede que tengas que añadir esta nueva acción:
String [] listActions = {
  "Print.generatePdf",
  "Print.generateExcel",
  "CRUD.new",
  "CRUD.deleteSelected",
  "Mode.detailAndFirst",
  "Mode.split", // HAS DE AÑADIR ESTO
  "List.filter",
  "List.customize",
  "List.orderBy",
  "List.viewDetail",
  "List.hideRows",
};
assertActions(listActions);
Si no te gusta este nuevo modo split, lo puedes quitar de tu applicación añadiendo la siguiente entrada en xava.properties:
defaultModeController=DetailList
En este caso el controlador de modo ya no es Mode sino DetailList, esto implica que has de cambiar tu pruebas junit:
// execute("Mode.list"); // NO si defaultModeController=DetailList en xava.properties
execute("DetailList.list"); // SÍ si defaultModeController=DetailList en xava.properties

Nueva acción CRUD.deleteRow - Cambios en jUnit

La acción CRUD.deleteSelected ha sido divida en CRUD.deleteSelected y CRUD.deleteRow. Si usas CRUD.deleteSelected con el argumento row, has de cambiarla por CRUD.deleteRow:
// execute("CRUD.deleteSelected", "row=2"); // NO, desde 4m5
execute("CRUD.deleteRow", "row=2"); // SI
Además, dado que CRUD.deleteRow está disponible por defecto en todos lo módulos, si usas assertActions() en tus pruebas puede que tengas que añadirla a la lista de acciones.

La vista (View) no es editable por defecto

A partir de ahora cuando se inicializa un módulo el objeto View no es editable. Esto no es un gran problema porque las acciones para nuevo y buscar establecen el estado correcto de editable en la vista. Pero si tienes una acción de nuevo o buscar personalizada puede que necesites modificarla para establecer el estado de editable explicitamente:
public class MiAccionBuscar extends ViewBaseAction {
 
  public void execute() throws Exception {
    ...
    getView().setKeyEditable(false);  // Has de llamar a setKeyEditable()
    getView().setEditable(true);      // y setEditalbe() explicitamente
    ...
  }
 
}

Para migrar de OpenXava 4m3 a OpenXava 4m4

CRUD.search ahora usa un diálogo - Cambios en jUnit

La acción CRUD.search ahora usa un diálogo para introducir los datos de búsqueda. Esto implica que todas tus pruebas junit que usen CRUD.search fallarán. Es decir, si tienes una prueba como la siguiente:
setValue("codigo", "1");
execute("CRUD.search");
assertValue("descripcion", "Número uno");
No funcionará. Has de reescribirla. Para hacerlo, tienes 2 opciones. La primera es adaptar tu prueba al nuevo comportamiento de la acción CRUD.search:
execute("CRUD.search"); // Muestra un diálogo
setValue("codigo", "1");
execute("Search.search"); // Hace la búsqueda y cierra el diálogo
assertValue("descripcion", "Número uno");
La segunda es cambiar "CRUD.search" por "CRUD.refresh", ya que la vieja CRUD.search ha sido renombrada como CRUD.refresh:
setValue("numero", "1");
execute("CRUD.refresh"); // En lugar de CRUD.search
assertValue("descripcion", "Número uno");
Además, dado que CRUD.refresh está disponible por defecto en todos lo módulos, si usas assertActions() en tus pruebas puede que tengas que añadirla a la lista de acciones.

Para migrar de OpenXava 4m2 a OpenXava 4m3

MapFacade.getValues() incluye el nombre del modelo en el resultado

MapFacade.getValues() ahora incluye el nombre del modelo en el resultado, con una entrada con la clave MapFacade.MODEL_NAME. Si usas la clases estándar de OpenXava (como View o PropertiesManager) todo funcionará bien, pero si tienes código personalizado puede ser que falle por culpa de esta nueva entrada inexeperada. En este caso quita la entrada de los valores, de esta forma:
Map valores = MapFacace.getValues("Persona", clave, miembros);
valores.remove(MapFacade.MODEL_NAME); // Puede que necesites esta línea

Método Classes.getSimpleName() eliminado

El método getSimpleName() de Classes ha sido eliminado. Usa getSimpleName() de Class available de Java 5 en su lugar.
Cambia esto:
Classes.getSimpleName(laClase);
por esto otro:
laClase.getSimpleName();

Para migrar de OpenXava 4m1 a OpenXava 4m2

Atributos mostrar-dialogo y ocultar-dialogo quitados de <accion/>

La forma declarativa de mostrar un diálogo ha sido sustituida por una programática en v4m2. La nueva forma es más flexible y requiere menos código, aunque la razón real para hacer este cambio es que la forma declarativa obliga al desarrollador a tocar controladores.xml cada vez que se hace una mejora en las acciones estándar con los diálogos. Es decir, con la forma declarativa muchas mejoras en OX requerirían muchas instrucciones de migración para que el desarrollador pueda actualizar su aplicación. Con el nuevo enfoque programático, el desarrollador puede actualizarse su versión de OX y disfrutar, sin tener que tocar su aplicación.
La mala noticia es que has de reescribir tu código con diálogos, ahora en vez de marcar tu acción con mostrar-dialogo y ocultar-dialogo, tienes que usar los métodos showDialog() y closeDialog(). Compara la nueva forma con la vieja para más detalles.

Las colecciones usan diálogos para editar, ver y añadir detalles - Cambios en acciones

Todas las acciones que extienden de CollectionBaseAction o CollectionElementViewBaseAction mantienen su comportamiento original, por tanto no necesitas hacer ningún cambio en la mayoría de tus acciones de colección. Pero, si tienes alguna acción de detalle que extienda directamente de ViewBaseAction quizás tengas que cambiar la forma de acceder a la vista padre. Recuerda que ahora estás dentro de un diálogo:
public class MiAccionDetalleParaColeccion extends ViewBaseAction  {
 
    public void execute() throws Exception {
        ...
        getView().setValue("nombre", "Pepe"); // Ahora getView() es la vista del diálogo
        getPreviousView().setValue("nombre", "Pepe"); // getPreviousView() es la vista
                                                      // que ha abierto el diálogo
        closeDialog();
    }
}
 
Es decir, quizás tengas que cambiar getView() por getPreviousView() en alguna de tus acciones.

Las colecciones usan diálogos para editar, ver y añadir detalles - Cambios en jUnit

Esto no afecta al código de tu aplicación, pero dado que el comportamiento de las colecciones ha cambiado, has de adaptar tu pruebas junit. La principal diferencia es que el usuario ahora usa un diálogo para editar la línea de detalle de la colección, por tanto el resto de las acciones y valores de la interfaz de usuario principal no están disponibles, ya que se usa un diálogo modal.
Ahora los miembros de la vista de detalle están en la vista raíz, por tanto tienes que quitar el prefijo de colección cuando referencias miembro del elemento de la colección:
// lineas es el nombre de la colección
setValue("lineas.cantidad", "6");  // Ahora ¡INCORRECTO! Has de quitar 'lineas'
setValue("cantidad", "6"); // ¡CORRECTO! Sin nombre de colección
También las acciones disponible al editar el elemento de una colección (por ende dentro de un diálogo) no usan ningún argumento:
execute("Collection.save", "viewObject=xava_view_section1_lineas"); // ¡INCORRECTO!
execute("Collection.save"); // ¡CORRECTO!
Si quieres acceder a las acciones o miembro de la vista principal, has de cerras el diálogo primero:
execute("Factura.editarLinea", "row=1,viewObject=xava_view_section1_details");
assertValue("cantidad", "234");
closeDialog(); // Necesario antes de ejecutar CRUD.save
execute("CRUD.save");
Al grabar el elemento de una colección el diálogo se cierra, por eso si quieres añadir otro detalle has de abrir otra vez el diálogo: