Thursday, October 20, 2016

Java 8: A Closer Look at Speedment 3.0.1 “Forest” Stream ORM

Following the Road

Forest.png
I have been contributing to the open-source project Speedment (which is a Stream ORM Java Toolkit and Runtime) and a new major version called 3.0.1 “Forest” was just released. Releases are named after the avenues in Palo Alto, California where most of the contributors work. Each new major release gets a new name by following Middlefield Road southwards. The new version is now modularized which helps developers keep up the good pace. There are also a large number of new features for Speedment users and in this article we will look into some of the things to discover!

Persistence

People used to older ORMs can now use Speedment in the same way when creating, updating or removing entities from a database. For example, we can create entities in a database “JPA-style” like this:
Hare hare = new HareImpl();
hare.setName("Flopsy");
hare.setAge(1);
hare.setColor("Gray");

entityManager.persist(hare);  // Persists (=inserts) the new Hare in the database

While this is not a big change, it is still convenient.

Declarative Stream Composition

Speedment database queries are expressed as operations on Standard Java 8 Streams. In the new version, the Speedment API provides methods that returns functions rather than operating on objects directly. This simplifies something called Declarative Stream Composition which simply means that it becomes easier and more efficient to write streams.

Let us take a closer look at an example where we want to join objects from two different tables. We have two tables “hare” and “carrot” where “carrot” has a field named “owner” that is a foreign key to the column “hare”.”id”. The task is to build a Map that contains all Hare entities as keys and a List of Carrot entities that belongs to a particular Hare via its foreign key, as values. This can be expressed like this:

Map<Hare, List<Carrot>> joinMap = carrots.stream()
    .collect(
        groupingBy(hares.finderBy(Carrot.OWNER)) // Applies the finderBy(Carrot.OWNER) classifier
    );

The goupingBy() method takes a Function that maps from a Carrot to a Hare entity. So, by working by methods that returns functions, our code becomes very compact. This also opens up future ways of optimizing the stream, since these functions can be identified and analyzed in the stream pipeline prior to the stream is started. It should be noted that both the collect() and groupingBy() methods are standard Java 8 methods.

Even Better Code Generation

Speedment generates code automatically from the database schema data. One good thing with Speedment is that we can see, understand and change the generated code. This makes things less “magic” compared to other ORMs and puts the developer in the driving seat. The new code generation functionalities include:

Support for Primitive Types

Now we can use primitive types like int, long or double for columns and improve both execution speed and memory usage. Nullable fields can be mapped to specialized Optional types like OptionalInt, OptionalLong and OptionalDouble consistent with Java 8 code styling.

Modular Code Generation

We can plug in our own code generation logic and adapt the default code generator. This comes in handy for us developers that might understand our domain model in depth and want to leverage that knowledge. When new functionality is added by customizing the code generator, these new features will be applied immediately to all generated code. Code the code and get leverage!

Compatibility Mode

Some older solutions are not prepared for Optional fields and so a new “compatibility” mode was added where, for example, a nullable integer will be returned as an Integer and not as an OptionalInt.

Configurable Name Space

We can now configure the code generator to put entities, managers and configuration objects individually on any namespace. This is good for modularized projects.

Improved Code Renderer

Speedment is using a Model View Controller (MVC) paradigm for code generation. This means that the code Model (which is an Abstract Syntax Tree) is separate from the actual code rendering (View). The Views have been updated and improved so it produces better looking code.

Checksum Protection

Manually changes classes are protected by checksums so that they are retained even if we decide to change the name space.

Increased Type Safety

Speedment can now map columns that take values from small sets of strings to Enums further improving type safety. When the generated code uses an Enum, any mismatch between the database model and the values used in the business logic will be found as early as possible by the compiler, instead of later in the development cycle.

Improved Logging for Transparency

Speedment has a new logging system to allow us to see the exact SQL code being sent to the database. This is good for transparency and allows us to see precisely what is happening under the hood. We can easily enable logging of all CRUD operations like this:

HaresApplication loggingApp = new HaresApplicationBuilder()
    .withPassword("secretDbPassword")
    .withLogging(STREAM)
    .withLogging(PERSIST)
    .withLogging(UPDATE)
    .withLogging(REMOVE)
    .build();

Manager<Hare> hares = loggingApp.getOrThrow(HareManager.class);

long oldHares = hares.stream()
    .filter(Hare.AGE.greaterThan(8))
    .count();

System.out.println("There are " + oldHares + " old hares");

This will produce the following log:
2016-10-19T20:50:21.957Z DEBUG [main] (#SELECT) - 
    SELECT COUNT(*) FROM `hares`.`hare` WHERE (`hares`.`hare`.`age` > ?), values:[8]

There are 30 old hares


Improved User Interface

The graphical tool has been improved in many ways. Now, we get warnings and tips that gives us better guidance. Several code generator configuration options have been added and we also see more relevant information when we select different configuration objects.

New Maven Goals

There are two new Maven goals; “clear” and “reload”, that can be used to automate and simplify the building process. The goal “clear” removes all generated code (that is not manually changed) and “reload” reloads the domain model directly from an existing database (metadata).

Take it for a Spin

Check out open-source Speedment on GitHub where there also is a Wiki and a quick start guide. Feel free to give feedback and join the discussion via Gitter.

Drive safely!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.