Tuesday, April 12, 2016

How to Generate Customized Java 8 Code with Plugins

One thing most programmers hate is to write boilerplate code. Endless hours are spent setting up entity classes and configuring database connections. To avoid this you can let a program like Speedment Open Source generate all this code for you. This makes it easy to get a database project up and running with minimal manual labour, but how do you maintain control of the written code when large parts of it is handed over to a machine?

Say that you have a database with a table "user" which has a column "gender", and you want that implemented as an enum in java. If you run Speedment and use it to generate code, the "gender" field will be represented as a String. The reason for this is that there isn’t any built-in mappers for converting between database ENUMs and custom java classes. This is one of those cases when you might feel that the generator is taking away control for you. Well, fear not, for since the 2.3 Hamilton release, you can get this same control by creating your own plugin for Speedment!

The Goal of this Article

In this example we have a database schema with a table called "Person". A person has an id, a name and a gender. The gender is declared as an ENUM with three possible values: "Male", "Female" and "Other". If we use the default settings in Speedment to generate this class, Speedment will consider the ENUM a String. There are some issues with this however. For an example, if you want to persist a new person into the database, there is nothing that prevents you from spelling a gender wrong and getting an exception when you do the insert. Instead, we want to define a java enum with the specified alternatives as constants. What would make the generated code more secure and easier to use.

We can achieve this using a plugin for Speedment!

Creating the Plugin Project

To do any custom modifications to the Speedment platform we will need to define a plugin. A plugin is a piece of software that can be plugged into the Speedment runtime from the pom.xml-file. The plugin resides in its own maven project and can be shared between projects.

Begin by creating a new Maven Project and declare Speedment as a dependency. You will not need the speedment-maven-plugin in this project.


<dependency>
    <groupId>com.speedment</groupId>
    <artifactId>speedment</artifactId>
    <version>${speedment.version}</version>
</dependency>

The plugin system revolves around two interfaces; Component and ComponentConstructor. A Component is a pluggable piece of software that can be executed as part of the Speedment lifecycle. Every component has a number of stages in which it is allowed to execute. These are "initialize", "load", "resolve" and "start".

The ComponentConstructor is a lightweight type that has a default constructor and a method for initializing new instances of the custom component. This is used by the maven plugin to setup the new code.

Here is how our two implementations will look:

CustomMappingComponent.java

public final class CustomMappingComponent 
extends AbstractComponent {
    
    CustomMappingComponent(Speedment speedment) {
        super(speedment);
    }

    @Override
    public void onResolve() {
        // Resolve logic here...
    }

    @Override
    public Class<CustomMappingComponent> getComponentClass() {
        return CustomMappingComponent.class;
    }

    @Override
    public Software asSoftware() {
        return AbstractSoftware.with(
            "Custom Mapping Component", 
            "1.0", 
            APACHE_2
        );
    }

    @Override
    public Component defaultCopy(Speedment speedment) {
        return new CustomMappingComponent(speedment);
    }
}
CustomMappingComponentInstaller.java

public final class CustomMappingComponentInstaller 
implements ComponentConstructor<CustomMappingComponent> {

    @Override
    public Component create(Speedment speedment) {
        return new CustomMappingComponent(speedment);
    }
}

We now have a bare-bone plugin that can be added to a Speedment project. The next step is to define the logic that maps between strings and genders. To this this, first we need the Gender enum.

Gender.java

public enum Gender {
    MALE   ("Male"), 
    FEMALE ("Female"),
    OTHER  ("Other");

    private final String databaseName;

    Gender(String databaseName) {
        this.databaseName = databaseName;
    }

    public String getDatabaseName() {
        return databaseName;
    }
}

If you store the enum values in upper-case in the database, this class could be much shorter since you could simply use the Enum.name()-method to get the database name, but this approach is better if you want flexibility in naming the constants.

Now for the final piece. We need to declare a type that implements the TypeMapper-interface in Speedment. A type mapper is really simple. It contains two methods for mapping to and from the database type as well as methods for retrieving the java class of both types.

StringToGenderMapper.java

public final class StringToGenderMapper implements TypeMapper<String, Gender> {
    
    @Override
    public Class<Gender> getJavaType() {
        return Gender.class;
    }

    @Override
    public Class<String> getDatabaseType() {
        return String.class;
    }

    @Override
    public Gender toJavaType(String value) {
        if (value == null) {
            return null;
        } else {
            return Stream.of(Gender.values())
                .filter(g -> g.getDatabaseName().equals(value))
                .findAny()
                .orElseThrow(() -> 
                    new UnsupportedOperationException(
                        "Unknown gender '" + value + "'."
                    )
                );
        }
    }

    @Override
    public String toDatabaseType(Gender value) {
        if (value == null) return null;
        else return value.getDatabaseName();
    }

    @Override
    public boolean isIdentityMapper() {
        return false;
    }
}

This new mapper also need to be installed in the Speedment platform. We can do that from the component we created earlier by modifying the onResolve()-method:

CustomMappingComponent.java

@Override
public void onResolve() {
    // Resolve logic here...
    getSpeedment().getTypeMapperComponent()
        .install(StringToGenderMapper::new);
}

Our new plugin is now done! Build the project and you are set to go!

Using the Plugin

To use a plugin in a project, you only need to modify the pom.xml-file of that project. Open up an existing Speedment project and locate the pom.xml-file. In it, you should be able to find the speedment-maven-plugin. To make your own plugin accessible for the maven plugin, you need to add it as a dependency inside the <plugin>-tag and add the ComponentInstaller to the configuration. Here is an example of how it can look:

pom.xml

<plugin>
    <groupId>com.speedment</groupId>
    <artifactId>speedment-maven-plugin</artifactId>
    <version>${speedment.version}</version>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- Our plugin project -->
        <dependency>
            <groupId>com.github.pyknic</groupId>
            <artifactId>custom-mapping-component</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
 
    <configuration>
        <components>
            <!-- Path to the component installer -->
            <component implementation="
com.github.pyknic.salesinfo.plugin.CustomMappingComponentInstaller
            " />
        </components>
    </configuration>
</plugin>

You also need to add the project as a runtime dependency since the new Gender-enum must be accessible from the generated code.


<dependencies>
    ...
    <dependency>
        <groupId>com.github.pyknic</groupId>
        <artifactId>custom-mapping-component</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
    ...
</dependencies>

Trying it out

That’s it! The plugin is installed! If you want to a particular column to be mapped to a Gender instead of a String, you can go into the User Interface, navigate to the particular column in the "Project Tree" and select your new Type Mapper in the dropdown list.

screenshot of the Speedment user interface

If you want to see a list of all the components and/or type mappers loaded into the platform, you can also go to "About" → "Components..." in the UI. There you should see the new component.

screenshot of the components dialog in the Speedment user interface

Summary

In this article you have learned how to create a custom plugin for Speedment that integrates a new Type Mapper from a String to a Gender enum. You have also learned how you can see which components are loaded into the platform and select which type mapper you want to use for each column.

PS: If you create some cool new mappers for your Speedment project, consider sharing them with the community in our Gitter chat!

Friday, April 8, 2016

Java 8: Bye Manual SQL, Hello Speedment!

Spire says Goodbye to the old way of writing
database applications in Java.

Most applications written in Java require some form of data storage. In small applications this is often realized using a primitive JDBC-connection that is queried using ordinary SQL. Larger systems on the other hand often use an Object Relational Mapping (ORM) frameworks to handle the database communication. There are pro’s and con’s with both of these approaches, but both tend to involve writing a lot of boilerplate code that looks more or less the same across every codebase. In this article I will showcase another approach to easy database communication using an open source project called Speedment.

What is Speedment?

Speedment is a developer tool that generates java classes from your SQL metadata. The generated code handles everything from setting up a connection to data retrieval and persistence. The system is designed to integrate perfectly with the Java 8 Stream API so that you can query your database using lambdas without a single line of SQL. The created streams are optimized in the background to reduce the network load.

Setting Up a Project

In this article I will write a small application that asks for the user’s name and age and persist it in a MySQL database. First of, we will define the database schema. Open up your MySQL console and enter the following:

CREATE DATABASE hellospeedment;
USE hellospeedment;

CREATE TABLE IF NOT EXISTS `user` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `name` varchar(32) NOT NULL,
    `age` int(5) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Next we will create our java project. Fire up your favorite IDE and create a new Maven Project from Archetype. Archetypes are template projects that can be used to quickly define new maven projects. Exactly how they are used differ between different IDEs. The following information will have to be entered:

Repository https://repo1.maven.org/maven2
GroupId com.speedment
ArtifactId speedment-archetype-mysql
Version 2.3.0

Similar archetypes are available for PostgreSQL and MariaDB as well.

On NetBeans, the archetype is usually found among the default ones indexed from the Maven Central Repository. When the project is created you should have something like this:

Launching the Speedment UI

Now then the project has been created it is time to start up the Speedment User Interface. This is done by executing the speedment:gui-maven goal. In NetBeans and IntelliJ IDEA, a list of available maven goals can be found from within the IDE. In Netbeans this is found in the Navigator window (often located in the bottom-left of the screen). The project root node must be selected for the goals to appear. In IntelliJ, the goals can be found under the "Maven Projects"-tab in the far right of the screen. You might need to maximize the "Project Name", "Plugins" and "speedment-maven-plugin"-nodes to find it. In Eclipse, you don’t have a list of goals as far as I know. Instead you will have to define the goal manually. There is a tutorial for doing this on the Speedment GitHub wiki.

When the user interface starts the first time it will ask for your email address. After that you can connect to your database.

The connection dialog will only allow you to choose between databases that you can connect to using the loaded JDBC-drivers. If you for example want to use a PostgreSQL-database, you should add the PostgreSQL-driver to the <dependencies>-tag of the speedment-maven-plugin section in the pom.xml-file and the re-run the UI.

Once you have connected to the database, the main window opens. On the left side you can see a tree-view of the database. In the middle is the workspace where things like database connection, code generation and entity naming can be configured. You can select what part of the project to configure by selecting other nodes in the tree.

In this case, we will simply press the "Generate"-button in the toolbar to generate a project using the default settings. We can now close the UI and return to our IDE.

Write the Application

Now when Speedment has generated all the boilerplate code required to communicate with the HelloSpeedment database we can focus on writing the actual application. Let’s open the Main.java-file created by the maven archetype and modify the main() method.


public class Main {
    public static void main(String... params) {
        Speedment speedment = new HellospeedmentApplication()
            .withPassword("secret").build();
        Manager<User> users = speedment.managerOf(User.class);
    }
}

In Speedment, an application is defined using a builder pattern. Runtime configuration can be done using different withXXX()-methods and the platform is finialized when the build()-method is called. In this case, we use this to set the MySQL password. Speedment will never store sensitive information like your database passwords in the configuration files so you will either have to have a unprotected database or set the password at runtime.

The next thing we want to do is to listen for user input. When a user starts the program, we should greet them and then ask for their name and age. We should then persist the user information in the database.


final Scanner scn = new Scanner(System.in);

System.out.print("What is your name? ");
final String name = scn.nextLine();

System.out.print("What is your age? ");
final int age = scn.nextInt();

try {
    users.newEmptyEntity()
        .setName(name)
        .setAge(age)
        .persist();
} catch (SpeedmentException ex) {
    System.out.println("That name was already taken.");
}

If the persistence failed, a SpeedmentException is thrown. This could for example happen if a user with that name already exists since the name column in the schema is set to UNIQUE.

Reading the Persisted Data

Remember I started out by telling you how Speedment fits in nicely with the Stream API in Java 8? Let’s try it out! If we run the application above a few times we can populate the database with some users. We can then query the database using the same users manager.


System.out.println(
    users.stream()
        .filter(User.ID.lessThan(100))
        .map(User::toJson)
        .collect(joining(",\n    ", "[\n    ", "\n]"))
);
This will produce a result something like this:

[
    {"id":1,"name":"Adam","age":24},
    {"id":2,"name":"Bert","age":20},
    {"id":3,"name":"Carl","age":35},
    {"id":4,"name":"Dave","age":41},
    {"id":5,"name":"Eric","age":18}
]

Summary

This article has showcased how easy it is to write database applications using Speedment. We have created a project using a maven archetype, launched the Speedment UI as a maven goal, established a connection with a local database and generated application code. We have then managed to do both data persistence and querying without a single row of SQL!

That was all for this time.

PS: Speedment 2.3 Hamilton was just released the other day and it contains a ton of really cool features for how you can manipulate the code generator to fit your every need. Check it out!

Tuesday, February 16, 2016

Equality vs Identity?

When storing objects in a Set, it is important that the same object can never be added twice. That is the core definition of a Set. In java, two methods are used to determine whether two referenced objects are the same or if they can both exist in the same Set; equals() and hashCode(). In this article I will explain the difference between equality and identity and also take up some of the advantages they have over each other.

Java offers a standard implementation of both these methods. The standard equals()-method is defined as an "identity" comparing method. It means that it compares the two memory references to determine if they are the same. Two identical objects that are stored in different locations in the memory will therefore be deemed unequal. This comparison is done using the ==-operator, as can be seen if you look at the source code of the Object-class.


public boolean equals(Object obj) {
    return (this == obj);
}

The hashCode()-method is implemented by the virtual machine as a native operation so it is not visible in the code, but it is often realized as simply returning the memory reference (on 32-bit architectures) or a modulo 32 representation of the memory reference (on a 64-bit architecture).
One thing many programmers choose to do when designing classes is to override this method with a different equality definition where instead of comparing the memory reference, you look at the values of the two instances to see if they can be considered equal. Here is an example of that:


import java.util.Objects;
import static java.util.Objects.requireNonNull;

public final class Person {

    private final String firstname;
    private final String lastname;

    public Person(String firstname, String lastname) {
        this.firstname = requireNonNull(firstname);
        this.lastname  = requireNonNull(lastname);
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + Objects.hashCode(this.firstname);
        hash = 83 * hash + Objects.hashCode(this.lastname);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final Person other = (Person) obj;
        if (!Objects.equals(this.firstname, other.firstname)) {
            return false;
        } else return Objects.equals(this.lastname, other.lastname);
    }
}

This comparison is called "equality" (compared to the previous "identity"). As long as two persons have the same first- and lastname, they will be considered equal. This can for an example be used to sort out duplicates from a stream of input. Remember that if you override the equals()-method, you should always override the hashCode()-method as well!

Equality

Now, if you choose equality over identity, there are some things you will need to think about. The first thing you must ask yourself is: are two instances of this class with the same properties necessarily the same? In the case of Person above, I would say no. It is very likely that you will someday have two people in your system with the same first- and lastname. Even if you continue to add more personal information like birthday or favorite color, you will sooner or later have a collision. On the other hand, if your system are handling cars and each car contains a reference to a "model", it can be safely assumed that if two cars both are black Tesla model S, they are probably the same model even if the objects are stored in different places in the memory. That is an example of a case when equality can be good.


import java.util.Objects;
import static java.util.Objects.requireNonNull;

public final class Car {
    
    public static final class Model {
        
        private final String name;
        private final String version;
        
        public Model(String name, String version) {
            this.name    = requireNonNull(name);
            this.version = requireNonNull(version);
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 23 * hash + Objects.hashCode(this.name);
            hash = 23 * hash + Objects.hashCode(this.version);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null) return false;
            if (getClass() != obj.getClass()) return false;
            final Model other = (Model) obj;
            if (!Objects.equals(this.name, other.name)) {
                return false;
            } else return Objects.equals(this.version, other.version);
        }
    }
    
    private final String color;
    private final Model model;
    
    public Car(String color, Model model) {
        this.color = requireNonNull(color);
        this.model = requireNonNull(model);
    }
    
    public Model getModel() {
        return model;
    }
}

Two cars are only considered the same if they have the same memory address. Their models on the other hand is considered the same as long as they have the same name and version. Here is an example of this:


final Car a = new Car("black", new Car.Model("Tesla", "Model S"));
final Car b = new Car("black", new Car.Model("Tesla", "Model S"));

System.out.println("Is a and b the same car? " + a.equals(b));
System.out.println("Is a and b the same model? " + a.getModel().equals(b.getModel()));

// Prints the following:
// Is a and b the same car? false
// Is a and b the same model? true

Identity

One risk of choosing equality over identity is that it can be an invitation to allocating more objects than necessarily on the heap. Just look at the car example above. For every car we create we also allocate space in memory for a model. Even if java generally optimizes string allocation to prevent duplicates, it is still a certain waste for objects that will always be the same. A short trick to turn the inner object into something that can be compared using identity comparing method and at the same time avoid unnecessary object allocation is to replace it with an enum:


public final class Car {
    
    public enum Model {
        
        TESLA_MODEL_S ("Tesla", "Model S"),
        VOLVO_V70     ("Volvo", "V70");
        
        private final String name;
        private final String version;
        
        Model(String name, String version) {
            this.name    = name;
            this.version = version;
        }
    }
    
    private final String color;
    private final Model model;
    
    public Car(String color, Model model) {
        this.color = requireNonNull(color);
        this.model = requireNonNull(model);
    }
    
    public Model getModel() {
        return model;
    }
}

Now we can be sure that each model will only ever exist at one place in memory and can therefore safely be compared using identity comparison. An issue with this however is that is really limits our extendability. Before with could define new models on the fly without modifying the source code in the Car.java-file, but now we have locked ourselves into an enum that should generally be kept unmodified. If those properties are desired, an equals comparison is probably better for you.

A finishing note, if you have overridden the equals() and hashCode()-methods of a class and later want to store it in a Map based on identity, you can always use the IdentityHashMap structure. It will use the memory address to reference its keys, even if the equals()- and hashCode()-methods have been overridden.

Wednesday, February 10, 2016

Cleaner Responsibilities - Get rid of equals, compareTo and toString

Have you ever looked at the javadoc of the Object-class in Java? Probably. You tend to end up there every now and then when digging your way down the inheritance tree. One thing you might have noticed is that it has quite a few methods that every class must inherit. The favorite methods to implement yourself rather than stick with the original ones are probably .toString(), .equals() and .hashCode() (why you should always implement both of the latter is described well by Per-Åke Minborg in this post).

But these methods are apparently not enough. Many people mix in additional interfaces from the standard libraries like Comparable and Serializable. But is that really wise? Why do everyone want to implement these methods on their own so badly? Well, implementing your own .equals() and .hashCode() methods will probably make sense if you are planning on storing them in something like a HashMap and want to control hash collisions, but what about compareTo() and toString()?

In this article I will present an approach to software design that we use on the Speedment open source project where methods that operate on objects are implemented as functional references stored in variables rather than overriding Javas built in methods. There are several advantages to this. Your POJOs will be shorter and more concise, common operations can be reused without inheritance and you can switch between different configurations in a flexible matter.

Original Code

Let us begin by looking at the following example. We have a typical Java class named Person. In our application we want to print out every person from a Set in the order of their firstname followed by lastname (in case two persons share the same firstname).

Person.java
public class Person implements Comparable<Person> {
    
    private final String firstname;
    private final String lastname;
    
    public Person(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }
    
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + Objects.hashCode(this.firstname);
        hash = 83 * hash + Objects.hashCode(this.lastname);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final Person other = (Person) obj;
        if (!Objects.equals(this.firstname, other.firstname)) {
            return false;
        }
        return Objects.equals(this.lastname, other.lastname);
    }

    @Override
    public int compareTo(Person that) {
        if (this == that) return 0;
        else if (that == null) return 1;

        int comparison = this.firstname.compareTo(that.firstname);
        if (comparison != 0) return comparison;

        comparison = this.lastname.compareTo(that.lastname);
        return comparison;
    }

    @Override
    public String toString() {
        return firstname + " " + lastname;
    }
}
Main.java
public class Main {
    public static void main(String... args) {
        final Set people = new HashSet<>();
        
        people.add(new Person("Adam", "Johnsson"));
        people.add(new Person("Adam", "Samuelsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Cecilia", "Adams"));
        
        people.stream()
            .sorted()
            .forEachOrdered(System.out::println);
    }
}
Output
run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)

Person implements several methods here to control the output of the stream. The hashCode() and equals() method make sure that duplicate persons can't be added to the set. The compareTo() method is used by the sorted action to produce the desired order. The overridden toString()-method is finally controlling how each Person should be printed when System.out.println() is called. Do you recognize this structure? You can find it in almost every java project out there.

Alternative Code

Instead of putting all functionality into the Person class, we can try and keep it as clean as possible and use functional references to handle these decorations. We remove all the boilerplate with equals, hashCode, compareTo and toString and instead we introduce two static variables, COMPARATOR and TO_STRING.

Person.java
public class Person {
    
    private final String firstname;
    private final String lastname;
    
    public Person(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }
    
    public final static Comparator<Person> COMPARATOR =
        Comparator.comparing(Person::getFirstname)
            .thenComparing(Person::getLastname);
    
    public final static Function<Person, String> TO_STRING =
        p -> p.getFirstname() + " " + p.getLastname();
}
Main.java
public class Main {
    public static void main(String... args) {
        final Set people = new TreeSet<>(Person.COMPARATOR);
        
        people.add(new Person("Adam", "Johnsson"));
        people.add(new Person("Adam", "Samuelsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Cecilia", "Adams"));
        
        people.stream()
            .map(Person.TO_STRING)
            .forEachOrdered(System.out::println);
    }
}
Output
run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)

The nice thing with this approach is that we can now replace the order and the formatting of the print without changing our Person class. This will make the code more maintainable and easier to reuse, not to say faster to write.

Wednesday, February 3, 2016

Definition of the Trait Pattern in Java

In this article I will present the concept of traits and give you a concrete example of how they can be used in Java to achieve less redundancy in your object design. I will begin by presenting a fictional case where traits could be used to reduce repetition and then finish with an example implementation of the trait pattern using Java 8.

Suppose you are developing a message board software and you have identified the following as your data models: “topics”, “comments” and “attachments”. A topic has a title, a content and an author. A comment has a content and an author. An attachment has a title and a blob. A topic can have multiple comments and attachments. A comment can also have multiple comments, but no attachments.

Soon you realise that no matter how you implement the three models, there will be code repetition in the program. If you for an example want to write a method that adds a new comment to a post, you will need to write one method for commenting topics and one for commenting comments. Writing a method that summarizes a discussion by printing out the discussion tree will have to take into consideration that a node can be either a topic, a comment or an attachment.

Since the inception of Java over 20 years ago, object-oriented programming has been the flesh and soul of the language, but during this time, other languages has experimented with other tools for organizing the structure of a program. One such tool that we use in Speedment Open Source is something called “Traits”. A trait is kind of a “micro interface” that describes some characteristic of a class design that can be found in many different components throughout the system. By referring to the traits instead of the implementing class itself you can keep the system decoupled and modular.

Let’s look at how this would change our example with the message board.

Now the different traits of each entity has been separated into different interfaces. This is good. Since Java allows us to have multiple interfaces per class, we can reference the interfaces directly when writing our business logic. In fact, the classes will not have to be exposed at all!

Traits have existed for many years in other programming languages such as Scala, PHP, Groovy, and many more. To my knowledge there is no consensus regarding what is considered a trait between different languages. On the Wikipedia page regarding traits it says that:

“Traits both provide a set of methods that implement behaviour to a class and require that the class implement a set of methods that parameterize the provided behaviour”

The following properties are named as distinctive for traits:

  • traits can be combined (symmetric sum)
  • traits can be overriden (asymmetric sum)
  • traits can be expanded (alias)
  • traits can be excluded (exclusion)

Since Java 8 you can actually fulfill most of these criteria using interfaces. You can for an example cast an implementing class of an unknown type to a union of traits using the and (&) operator, which satisfies the symmetric sum criteria. A good example of this is described here. By creating a new interface and using default implementations you can override some methods to fulfill the asymmetric sum criteria. Aliases can be created in a similar way. The only problem is exclusion. Currently java has no way of removing a method from inheritance so there is no way to prevent a child class from accessing a method defined in a trait.

If we return to the message board example, we could for an example require the implementing class to have a method getComments, but all additional logic regarding adding, removing and streaming over comments could be put in the interface.


public interface HasComments<R extends HasComments<R>> {
    
    // one method that parameterize the provided behaviour
    List<Comment> getComments();

    // two methods that implement the behaviour
    default R add(Comment comment) {
        getComments().add(comment);
        return (R) this;
    }

    default R remove(Comment comment) {
        getComments().remove(comment);
        return (R) this;
    }
}

If we have an object and we want to cast it to a symmetric sum of HasComments and HasContent, we could do it using the and (&) operator:


final Object obj = ...;
Optional.of(obj)
    .map(o -> (HasComments<?> & HasContent<?>) o)
    .ifPresent(sum -> {/* do something */});

That was all for this time!

PS: If you want to read more about traits as a concept, I really suggest you to read the Traits: Composable Units of Behaviour paper from 2003 by N. Schärli et al.