openxava / documentation / Migration

How to update your project to the latest OpenXava?

Edit the pom.xml file in your project and change the value of the openxava.version property to point to the latest OpenXava version, thus:

<properties>
    <openxava.version>7.0</openxava.version>
    ...
</properties>

Rebuild your project:


If current version is 6.x you should follow the instructions in Migration from OpenXava 6.6.3 to OpenXava 7.0 section first.

Finally, revise the instructions below to adapt your code.

Migration from OpenXava 6.6.3 to OpenXava 7.0

Convert your project to Maven structure

OpenXava 7 is Maven compatible, so the classic structure of an OpenXava project is no longer recognized. You have to turn your project into a standard Maven project. Fortunately, all your current code is valid, only that it have to be placed in different folders. If you're not familiar with Maven, look at the standard directory layout of a Maven project.

The easier way to migrate to Maven is creating a new project using OpenXava 7.0, and then copying the source code and resources from your current project to the new one. So, first create a new OpenXava project using Openxava Studio 7, for that you can follow the instructions in Getting started guide.

The next step is to copy all your source code and resources from the old project to the corresponding folder in the new project, as following:

The test code is in a different folder in Maven, so you should copy:

The above is enough for most applications.

The web code now is in src/main/webapp instead of web. First, create a folder called xava in src/main/webapp to put there your web code.
If you have your own custom editors you have to copy the editors code:

Also copy:

The servlets.xml, filters.xml and listeners.xml files are no longer supported. You can copy their content to the web.xml, that now is empty and ready for your own things, in src/main/webapp/WEB-INF. If you use @WebServlet, @WebFilter and @WebListener annotations you don't need to do any change.

If you use an extra third party library in your application you have to add a dependency in the pom.xml file in the root of your project. You no longer are going to copy jars in web/WEB/lib. If you're not familiar with Maven read about Maven dependecy mechanism.

If you use a database other than HSQLDB you have to add the dependency for your JDBC driver. For example, if you use MySQL add the next entry to your pom.xml:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

For other database just ask Google, something like "maven dependency oracle" for example. In order your JDBC driver will be downloaded and included in your project you have to execute "mvn package" in your project. You can do it from command line (if you have Maven installed in your machine) or from OpenXava Studio (not needed to have Maven installed), with Run As > Maven Build... in your project and typing "package" as goal. This step is not needed if you use HSQLDB as database.

Now you can run your application. Put your mouse on src/main/java of your project and choose Run As > Java Application. From now on, you can modify your code and relaunch your application as always, even if you launch it in debug mode you can modify the code and see the result without relaunch the application. That it, you can work in development as you're used to do.

We no longer use Ant. Now you do everything using Maven commands. If you're not familiar with Maven read some Maven introduction documentation. For example, to create the war for deploying in production you use "mvn package", and get the war ready to be deployed in Tomcat in the target folder of your project.  You can run all maven commands from OpenXava Studio, with the option Run As on your project.

Note that when you created the project with OpenXava the project name is in lowercase, this is because the nomenclature for Maven is to use lowercase for the name of artifactId, that matches with project name and deliverable (the generated war). For new projects you should user lowercase for project name. However, for years we have promoted first uppercase letter for project name in documentation, so probably you have your old project with its name starting with uppercase. You can choose migrating to lowercase and adopt the Maven standard way, but keep in mind that it would change the browser URL used by your users.
That is, if your application name was "Accounting" and you change it to "accounting", now the next URL: https://yoursite.com/Accounting does not work anymore. Now you have to use https://yoursite.com/accounting (with accounting in lowercase). If that is acceptable for your users, good. If not, you can rename your Maven project so it uses your old project name (Accounting in this case) and your users can continue using the original URLs.
Let's say that you want to change the project name from "accounting" to "Accounting". For that edit pom.xml and change:
<artifactId>accounting</artifactId>
By:
<artifactId>Accounting</artifactId>
Also in pom.xml change:
<finalName>accounting</finalName>
By:
<finalName>Accounting</finalName>
Then edit application.xml (in src/main/resources/xava) and change:
<application name="accounting">
By:
<application name="Accounting">
Also in the launcher class, that is accounting.java in the package com.yourcompany.accounting.run, change:
AppServer.run("accounting");
By:
AppServer.run("Accounting");
Finally, you should do in your project Run As > Maven clean (mvn clean) and Run As > Maven Build... typing package as goal (mvn package).

Hibernate upgraded from 5.3 to 5.6

We have done a hard work to adapt OpenXava in order it works nicely with Hibernate 5.6. However, you can find problems in your own JPA/Hibernate code. If you use JPA API everything should work as it, but there are new bugs in Hibernate 5.6 that can cause your current code to fail. We found some of them.

Join required in reference in key

With Hibernate 5.3 when you use a property of a reference and this reference is part of the key, you don't need to add an explicit join in the query. This is in this way no matter the deep level. In Hibernate 5.6, you don't need to add the join if you have only one level of reference, but if you have a second level, you have to add it, if the second level has a composite key.

Saying it with code. If you have:

@Entity
public class TransportCharge {
	
    @Id @ManyToOne
    private Delivery delivery;

    ...
	
}

@Entity
public class Delivery {
	
    @Id 
    private int number;

    @Id @ManyToOne
    private Invoice invoice;

    ...
	
}

@Entity
public class Invoice {
	
    @Id 
    private int year;
	
    @Id 
    private int number;

    ...
	
}

With the above code the next query run nicely with Hibernate 5.3:

String queryString="from TransportCharge o where o.delivery.invoice.year = :delivery_invoice_year";
Query query = XPersistence.getManager().createQuery(queryString);
query.setParameter("delivery_invoice_year", 2022);

But it fails with Hibernate 5.6. Curiously if you do the query against Delivery asking by invoice.year it works, it only fails with 2 levels or more. Moreover, if Invoice would have a single key, instead of a composite one, it works too. Hibernate 5.6 fails when you combine more than one level with composite keys.

Don't worry, the solution is easy, just add an explicit join for the first reference. That it, in the next way it works with Hibernate 5.6:

String queryString="from TransportCharge o join fetch o.delivery d where d.invoice.year = :delivery_invoice_year";
Query query = XPersistence.getManager().createQuery(queryString);
query.setParameter("delivery_invoice_year", 2022);

The solution is the join fetch o.delivery d. Conclusion, if some query fails for you with Hibernate 5.6 try to add an explicit join to your reference.

Schema is not created automatically

A new bug of Hibernate 5.6 is that it no longer recognizes javax.persistence.create-database-schemas, so if you have the next configuration in your persistence.xml:

<persistence-unit name="default">
    ...
    <properties>
        <property name="javax.persistence.schema-generation.database.action" value="update"/>
        <property name="javax.persistence.create-database-schemas" value="true"/> 
        <property name="hibernate.default_schema" value="MYSCHEMA"/>
    </properties>
</persistence-unit>

With Hibernate 5.3 it created the MYSCHEMA schema and then the tables inside, however with Hibernate 5.6 the MYSCHEMA schema is not created, hence the tables are not create neither. The solution is to create the MYSCHEMA schema by hand. You have to connect to your database with your database explorer and execute a CREATE SCHEMA MYSCHEMA (or equivalent) sentence. After it, you can start the application and the tables will be created.

XHibernate utility class removed

XHibernate utility class has been removed because it was used in XML components applications, in JPA applications we use XPersistence instead, and we have removed XML components support in v7.0. Hibernate API is still available. In the rare case you use XHibernate in some point of your code, change:

Session session = XHibernate.getSession();
session.save(customer);

By:

Session session = (Session) XPersistence.getManager().getDelegate();
session.save(customer);

That is, you can get a Hibernate Session object from the JPA manager. Another alternative would be to get the Hibernate session directly in the Hibernate way, but in this case you have to create the SessionFactory by yourself and be responsible of closing the transaction and session.

Project resources in different place (for JUnit tests)

Given that now your OpenXava projects have a standard Maven structure, most of the resources of your project are in a different place now, so if you use them from some JUnit test you have to adapt the path of the resource.
For example, if you have the next line in a JUnit test:
uploadFile("scripts", "reports/Corporation.html");
You should change it by:
uploadFile("scripts", "src/main/resources/reports/Corporation.html");
Note as we changed reports by src/main/resources/reports in the path, because now all the resources are in src/main/resources.

HtmlUnit upgraded from 2.32 to 2.63 (for JUnit tests)

If you use for testing the methods from ModuleTestBase you don't need to touch anything. However, if you use directly the API of HtmlUnit, something that can happen if you use getWebClient() or getHtmlPage() in your test, in that case maybe you need to adapt your code. HtmlUnit keeps its tradition of adding backward incompatible changes in each new minor version, to do this they change capriciously the name of methods, move things from a package to another or change the behavior of some method. We found the next things, for example.
The asText() method of HtmlElement has been rename as asNormalizedText(), so if you have a code like this in your test:
HtmlElement card = body.getElementsByAttribute("div", "class", "ox-card").get(2);
assertEquals("Unit price: 0.00, Unit price in pesetas: 0"), card.asText());
Change it by:
HtmlElement card = body.getElementsByAttribute("div", "class", "ox-card").get(2);
assertEquals("Unit price: 0.00, Unit price in pesetas: 0"), card.asNormalizedText());
Adding insult to injury asNormalizedText() does not behave exactly as the old asText(), now it changes all new lines by a single \n. It means that maybe you have to change some test code if you use asText() and examine the new lines. For example, if you have the next test code:
assertDiscussionCommentText("discussion", 0, Strings.multiline("admin - Now", "Hi, it's me")); 
Change it by:
assertDiscussionCommentText("discussion", 0, "admin - Now\nHi, it's me");
Note that we no longer use the Strings.multiline() utility and we use single \n. In this case you have not used asNormalizedText() directly, but assertDiscussionCommentText() from ModuleTestBase that uses asNormalizedText() for its implementation. That is, some methods of ModuleTestBase are affected by this new behavior, among them assertValueInList() for Card list format, now you have to use a single \n instead of \r\n. So you have to change:
assertValueInList(2, "XAVA\r\n3\r\nUnit price: 0.00");
By:
assertValueInList(2, "XAVA\n3\nUnit price: 0.00");
Another change in the way HtmlUnit behaves is that is uses UNICODE characters instead of ANSI characters, so if you test for special characters you have to adapt your code. For example, you should change:
assertEquals(
    "javascript:openxava.executeAction('openxavatest', 'Carrier', 'Effacer l" 
        + (char) 145 // ANSI  
        +"entité courante: Etes-vous sûr(e) ?', false, 'CRUD.delete')", 
    deleteLink.getHrefAttribute());
By:
assertEquals(
    "javascript:openxava.executeAction('openxavatest', 'Carrier', 'Effacer l" 
        + (char) 8216 // UNICODE
        +"entité courante: Etes-vous sûr(e) ?', false, 'CRUD.delete')", 
    deleteLink.getHrefAttribute());
Note as we changed 145 by 8216. Look at this table to know the mapping between ANSI and UNICODE.
Now in @HtmlText or @Stereotype("HTML_TEXT") properties you get the real content, including the HTML tags, surely because a better JavaScript support in HtmlUnit. Therefore, if you have a @HtmlText property called description, change:
assertValue("description", "This is the big jUnit discussion");
By:
assertValue("description", "<p>This is the big jUnit discussion</p>");
Also, getValue() and assertValue() now do a trim() to work better with the new HtmlUnit behavior, so you have to change:
assertValue("city", "46540 ");
By:
assertValue("city", "46540");
Note as we have removed the space after 46540.
The new HtmlUnit requires you to reload the page in order that CSS works correctly, so if you activate CSS for your test you must do a reload() after it. In this way:
getWebClient().getOptions().setCssEnabled(true); // If you do this then...
reload(); // ...you have to add this line
Curiously, adding reload() is not always needed, just add it where you find that tests with CSS start to fail.

Apache POI upgraded from 3.15 to 5.1

Apache POI is a Java library used to manipulate Microsoft Documents, like Excel. JasperReports uses it so it has been needed to upgrade POI in order the latest JasperReports works. If you don't use POI directly you don't need to do anything. However if you use the POI API in your code, you have to adapt it, because they have refactored all the code changing names and places, just to be backward incompatible. These are some of the changes we have noted.
They have turned all final variables into enums, these are some examples:
CellType.NUMERIC // Instead of Cell.CELL_TYPE_NUMERIC
HyperlinkType.FILE // Instead of Hyperlink.LINK_URL
FillPatternType.SOLID_FOREGROUND // Instead of CellStyle.SOLID_FOREGROUND
HSSFColor.HSSFColorPredefined.RED // Instead of HSSFColor.RED
BorderStyle.THIN // Instead of CellStyle.BORDER_THIN
HorizontalAlignment.LEFT // Instead of CellStyle.ALIGN_LEFT
If you need to use the short values of the old final variables you can use the getCode() and valueOf() methods present in most of the new enums.
The setCellType() method of Cell has been removed:
Cell cell ... 
// cell.setCellType(Cell.CELL_TYPE_FORMULA); // No longer exist, not needed
cell.setCellFormula(text);
setCellType() is no longer needed because the Cell infers the type from the cell value.
The setBoldweight() method of Font has been removed. So you have to change this:
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
By:
font.setBold(true);
Note the new setBold() method in Font.
There are more incompatible changes in the new Apache POI version. Don't worry, the compiler will advice you of them, and StackOverflow will help you to fix them.

Migration to OpenXava 6.6.3

For migrating to OpenXava 6.6.3 from any older OpenXava version (since 1.0):

Follow the OpenXava 6.x migration instructions