Self-referencing generics, wait, what ?
Tags: java, pattern, builder
Published: 2023-11-20 21:12:09

Have you ever seen some declaration of class with a generic type referencing itself ?

```java
public class BaseProject<T extends BaseProject> { ... }

public class FileProject extends BaseProject<FileProject> { ... }
```

It took me some time to understand the purpose of this. Now that this is clear for me, I decided to write something in order to explain it using a simple example: `Builders`.

#### Introduction

Nowadays, library author provides usually `builder` to ease the usage of their objects. 
This allows you to easily create complex objects by chaining methods. 

A cache can easily be created like: 

```java
Cache<String> cache = Caffeine.newBuilder()
    .expireAfterWrite(1, TimeUnit.MINUTES)
    .maximumSize(100)
    .build();
```

Crafting a builder can be summed up by creating a class (usually nested) that will expose a method for each property with can set in the object. This builder also exposes a `build()` method that will call the parent class constructor using data stored in the builder. 

#### How to design a simple builder

Let's say we have the following class: 

```java
public class Project {
    private final String name;
    private final File path;
    private final Type type;
    ...
}
```

Creating a new instance of this class can easily be done by calling a constructor with the required arguments:

```java
var myProject = new Project(name, path, type);
```

However, it can become complicated when some parameters are optional, we don't want to have all possible constructors declared in our class. 
This is where a builder become really handy. 

Let's implement it in our `Project` class:

```java    
public static class ProjectBuilder {
    private String name;
    private File path;
    private Type type;

    public Builder name(String name) {
        this.name = name;
        return this;
    }

    public Builder path(File path) {
        this.path = path;
        return this;
    }
 
    public Builder type(Type type) {            
        this.type = type;
        return this;
    }

    public Project build() {
        return new Project(name, path, type);
    }
}
```

This builder can be used in the following way: 

```java
var myProject = new ProjectBuilder()
           .name("my-project")
           .type(Type.File)
           .build();
```

Thus, creating a complex object can be as easy as chaining methods based on property we want to set. 

#### What about inheritance

In some case, the class we try to build may extend some classes, and share some property with a super class. 
For example, our project could be more specific, instead of having a `type` property we could have a specific class for each type:

```java
public class BaseProject { 
    protected final String name;
    ...
}
public class FileProject extends BaseProject { 
    private final Path path;
    ...
}
public class UrlProject extends BaseProject { 
    private final URI link;
    ... 
}
```

Regarding `builder`, we could decline a specific builder for each subtype, such as:

```java
public class FileProjectBuilder {
    private String name;
    private File path;

    public FilePojectBuilder name(String name) {
        this.name = name;
        return this;
    }

    public FilePojectBuilder path(File path) {
        this.path = path;
        return this;
    }

    public FileProject build() { ... }
}
```

As we can see with this example, **all properties of the `BaseProject` must be declared in the builder** alongside specific properties.

How could we fix that ? 

Well, we could use inheritance, such as:

```java
public abstract class BaseProjectBuilder {
    protected String name;

    public BaseProjectBuilder name(String name) {
        this.name = name;
        return this;
    }

    public abstract Project build();
    ...
}

public class FileProjectBuilder extends BaseProjectBuilder {
    private File path;

    public FilePojectBuilder path(File path) {
        this.path = path;
        return this;
    }

    @Override
    public FileProject build() {
        ...
    }
}

public class UrlProject extends BaseProject {
    private URI link;

    public UrlPojectBuilder link(URI link) {
        this.link = link;
        return this;
    }

    @Override
    public UrlProject build() {
        ...
    }
}
``` 

With this code, the `BaseProjectBuilder` takes care of setting `BaseProject` properties and specific implementations take care of setting specific properties.

```java
var myFileProject = new FileProjectBuilder()
                 .name("my-project")
                 .path(new Files("/src"))
                 .build();
```

Unfortunately, this does not work ... The type returned by the `name()` method is a `BaseProjectBuilder` while the `path` method is part of the `FileProjectBuilder` subclass. We just lost the subtype when calling the `name()` method. 

Can we fix that ? **Yes**, by using self referencing generics.
 
First we need to update the `BaseProjectBuilder` class definition in the following way:

```java
public abstract class BaseProjectBuilder<T extends BaseProjectBuilder> { ... }
```

Then all subclass will be updated to specify a type in there definition: 

```java
public class FileProjectBuilder extends BaseProjectBuilder<FileProjectBuilder> {
   ... 
}

public class UrlProjectBuilder extends BaseProjectBuilder<UrlProjectBuilder> {
   ...
}
```

Thanks to this generic type, we can now implement a `self()` method in the `BaseProjectBuilder` class and update the problematic `name()` method as well:

```java
public abstract class BaseProjectBuilder<T extends BaseProjectBuilder> { 

    ... 

    public T name(String name) {
        this.name = name;
        return self();
    }
        
    public T self() {
        return (T) this;
    }

}
```

Now, the `name` method will return the correct type and the following code can be compile:

```java
var myFileProject = new FileProjectBuilder()
                 .name("my-project")
                 .path(new Files("/src"))
                 .build();
```


#### What about Lombok ? 

Lombok allows you to easily generate `Builder` using the `@Builder` annotation on the class level. 

In that specific case we can define a constructor in the subclass and annotate the constructor directly.


#### Conclusion

Generics are really powerful and can help a lot when it come to handling types. As well as code organisation, we can also find patterns using generics.