Bugfix version 1.4.1 released

2019-09-09

We released Fastnate 1.4.1 as intermediate release with fixes for three reported bugs.
Young Nate

This is Nate.

Nate is a software developer. (I know, we've just lost half of the audience ... )

Nate is a Java developer. (Now we've lost the other half, except ... you)

Nate likes many things. He likes programming, he likes agile software development, he likes if things fit together.

Cool Nate

Nate has worked in many software projects that make use of a database.

So he learned to know JPA to map his objects to a relational database. He learned that if he refactors one of his entity classes, he doesn't have to think about the generated SQL, as JPA will do that for him. He has learned that JPA is fast for read operations on the database. And he has learned that JPA is fast enough for atomic write operations.

And now Nate is a cool Java developer.

Unhappy Nate

What Nate is missing in JPA is a strategy for importing initial data or test data into either the development or the production database.

If the customer has an existing database which hasn't to be changed for the tasks that Nate is working on, everything is fine.

But if either he starts with an empty database, or if the existing database has to be changed, or if he has no access to that database, than he needs some way to fill the data into his database. Unfortunately this situation is the case for the majority of his projects.

Nate found out that he has two options:

  1. He could use JPA to create and fill his database on the fly.

    The biggest problem with that is, that JPA is slow for write operations, as in most cases it needs some additional read statements before or after the update, it needs to update resp. flush its caches and it has a complex transaction management. During the lifetime of an application this is not really a problem, but during setup of a database this can take some time. And if he (or one of his teammates) changes the content or layout of the database, he has to do it again and again.

    And eventually it may block refactorings or enhancements, because nobody likes to wait.

  2. As another option he could write all the necessary SQL insert and update statements by hand and import these statements through one of the SQL interfaces.

    This option is much faster than the JPA alternative, but has some other disadvantages. First of all he needs to know SQL. Although it is advisable to understand SQL for working with JPA, it is not really necessary. Furthermore he has to know the exact design as created by his JPA library. And the written SQL would be specific for that JPA library and, more important, for his current database. If Nate switches to another database type or version he has to change the SQL. If he uses a different database type during development and testing (e.g. H2 and Oracle), he would have to maintain two slightly different SQL statement sets.

    And finally it would block refactorings as well, because if he changes one of his entity classes he needs to change the SQL as well.

Nate has tried both options, even at the same time. And in every new project he has the feeling that there has to be a third option.

Fast Nate

So Nate thought, and he thought, and finally he got the idea.

If he uses the JPA entities to generate the SQL statements ... that would be fast, that would be database independent, he could refactor as he like, he wouldn't have to think about SQL, ...

But he couldn't use any of the existing JPA libraries, as these were not designed to create an offline SQL script.

So Nate decided to write his own library on top of JPA. It should not replace any existing JPA library, it was meant as an add-on.

And finally Nate managed it. And now he is ... the Fast Nate.

Comparison of available options

A short summary of the pros and cons of every available option for generating data.

Feature JPA SQL Fastnate
Independent of database dialect yes no yes
Easy refactoring of entity classes yes no yes
Generate offline, apply later no yes yes
Fast import no yes yes*
A comparison chart of the performance of Hibernate and Fastnate
comparison chart

The documentation and examples of Fastnate are maintained in the Fastnate Wiki.

Some Wiki shortcuts:

The latest generated API documentation can be found in the API section.

Some API shortcuts:

Finally a small appetizer of how to use the Fastnate Data library:

public class TestData extends AbstractDataProvider {

    /** A list that contains all the created data. */
    @Getter
    private final List<ExampleEntity> entities = new ArrayList<>();

    /** Create the entities. */
    public void buildEntities() throws IOException {
        this.entities.add(new ExampleEntity("Example Entity"));
        
        ExampleEntity entity2 = new ExampleEntity("Example Entity 2");
        entity2.getChildren().add(new ExampleEntity("Child"));
        this.entities.add(entity2);
    }

}

See the download section for a description how you can add the Fastnate library to your build path.

You can generate the SQL for your entities either during build time or during application startup with one of the following options:

Use the Maven build task

You can use the importData task to generate an offline SQL file during build time:

<build>
	<plugins>
		<plugin>
			<groupId>org.fastnate</groupId>
			<artifactId>fastnate-maven-plugin</artifactId>
			<version>1.4.1</version>
			<executions>
				<execution>
					<goals>
						<goal>import-data</goal>
					</goals>
					<configuration>
						<packages>...my data provider package...</packages>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>
Command line

You can generate the SQL file from the command line:

java -cp ...;fastnate-data.jar;fastnate-generator.jar -Dfastnate.data.provider.packages=...my data provider package... org.fastnate.data.EntityImporter [SQL file]

If you don't specify any SQL file, the default is used: data.sql

Application startup

You can import your data on application startup, for example directly after a clean database is created by Hibernate. For that you need to define a SessionFactoryObserver:

public class DatabaseStartupImport implements SessionFactoryObserver {

	public void sessionFactoryCreated(final SessionFactory factory) {
		// Only import, if we have just created an empty database:
		final SchemaAutoTooling autoTooling = factory.getSessionFactoryOptions().getSchemaAutoTooling();
		if (autoTooling == SchemaAutoTooling.CREATE || autoTooling == SchemaAutoTooling.CREATE_DROP) {
			// Find a connection:
			final SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) factory;
			try (Connection connection = sessionFactoryImplementor.getServiceRegistry()
					.getService(ConnectionProvider.class).getConnection()) {
				// Import data
				final Properties settings = new Properties();
				settings.setProperty(EntityImporter.PACKAGES_KEY, "... my data provider package ...");
				new EntityImporter(settings).importData(connection);
			} catch (final SQLException | IOException e) {
				throw new IllegalStateException("Could not import SQL data: " + e, e);
			}
		}
	}
}

To tell Hibernate to use that observer you need to define a hibernate.ejb.session_factory_observer in your persistence.xml:

<persistence ...>
	<persistence-unit ...>
		<properties>
			<property name="hibernate.ejb.session_factory_observer" value="...mypackage...DatabaseStartupImport" />
			
			<!-- Tell Hibernate to recreate the schema on every startup. You can define that as a system property, too: -->
			<property name="hibernate.hbm2ddl.auto" value="CREATE" />
			
		</properties>
	</persistence-unit>
</persistence>

You can obtain Fastnate in different flavours. For an overview of available versions see below.

Include Fastnate as Maven dependency
Fastnate is included in the central Maven repository. Just add it to your pom.xml:
<dependencies>
	<!-- Use the DataProvider -->
	<dependency>
		<groupId>org.fastnate</groupId>
		<artifactId>fastnate-data</artifactId>
		<version>1.4.1</version>
	</dependency>
	<!-- Or use the generator itself -->
	<dependency>
		<groupId>org.fastnate</groupId>
		<artifactId>fastnate-generator</artifactId>
		<version>1.4.1</version>
	</dependency>
</dependencies>
Standalone
If you want to use Fastnate as standalone library, you need to download it from our binary repository:
Snapshot builds
To use the latest development snapshots as dependency you need to add our binary repository to your settings.xml or pom.xml :
<repositories>
	<repository>
		<id>fastnate.org</id>
		<url>https://download.fastnate.org/repository</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
</repositories>
After that you can switch to version 1.5.0-SNAPSHOT in your dependency declaration.
Latest sources
The sources are available in GitHub: You can browse or clone the source here:

Stable versions

1.0.0-RC1
Support for Java 7 and JBoss AS 7.x / Hibernate 4
1.1.0
Support for Java 8 and WildFly 10 / Hibernate 5
1.2.0
Better support for different generator types and for MySQL
1.3.0
Support for Microsoft SQL server and for writing statements to a database
1.4.0
Improved performance and JPA compatibility and support to write PostgreSQL bulk files
1.4.1
Bugfix release

Changelog

The changelog is maintained in the repository in the file changelog.md.

Road map

An overview of upcoming versions can be found in our issue tracker.

Fastnate is licensed under the Apache License, Version 2.0 (the "License"), you may not use it except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Fastnate was initially created for the eGovernment Application Framework at ]init[ AG.

In 2014 the ]init[ AG gave their pemission to publish Fastnate as standalone library under an OpenSource license.

Fastnate is now maintained by Tobias Liefke.

Contributors:

If you would like to contribute to Fastnate, you can create a pull request.

Or you create a new issue in the Fastnate bug tracking system and add your patch to it.