Objectos Weekly #004: Type annotations, canonical names and inner classes
Tags: java, weeklyretro
Published: 2022-12-09 13:27:41

Welcome to Objectos Weekly issue #004. 

I was writing this issue when the power in my apartment went out and I heard a loud noise outside. I looked outside from my balcony and I saw that the tree in front of my building had fallen taking a power line with it. Scary: a live power line was exposed right at the sidewalk. It burned a hole through the pavement. Luckily, there was no one there when it happened.

The power was restored later the same day. But it was already too late to do any meaningful work; I finished this issue the next day.

## Type annotations, canonical names and inner classes

I have recently learned a detail regarding [type annotations](https://docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html), [canonical names](https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.7) and [inner classes](https://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html).

Suppose a class `Example` which is a subclass of the `Super` type:

```java
package post;

import post.util.Super;

public class Example extends Super {}
```

Notice that the superclass is in a different package of the subclass. For this reason, a import declaration was required.

Let's annotate the superclass with a `Nullable` annotation.

```java
package post;

import post.annotation.Nullable;
import post.util.Super;

public class Example extends @Nullable Super {}
```

The annotation might indicate to a hypothetical static analysis tool that the superclass fields can hold `null` values.

The code above compiles without errors.

### Referring to the superclass by its canonical name

What happens if we use the canonical name of the superclass instead? We can remove the import declaration, like so:

```java
package post;

import post.annotation.Nullable;

// does not compile!
public class Example extends @Nullable post.util.Super {}
```

After this change, the code no longer compiles! `javac` issues the following error message:

```
$ javac -d /tmp src/main/java/post/{,annotation,util}/*.java
src/main/java/post/Example.java:10: error: cannot find symbol
public class Example extends @Nullable post.util.Super {
                                       ^
  symbol: class post
1 error
```

It seems `javac` was expecting a class right after the `Nullable` annotation. Eclipse JDT error message gives more information:

> Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays) 

OK, let's try to fix it then.

### Fixing the compilation error

We must write the annotation right before the simple name of the class, like so:

```java
package post;

import post.annotation.Nullable;

public class Example extends post.util. @Nullable Super {}
```

Notice how the annotation is after the trailing _dot_ character of the package name.  

The code now compiles without errors:

```
$ javac -d /tmp src/main/java/post/{,annotation,util}/*.java

[no errors emitted]
```

Well, I didn't know about that.

### Why though?

I don't know for sure. But I think **inner classes** are one of the reasons.

In the [previous issue](https://www.objectos.com.br/blog/objectos-weekly-003.html) I talked about [inner classes](https://www.objectos.com.br/blog/objectos-weekly-003.html#the-qualified-superclass-constructor-invocation) and [qualified superclass constructor invocations](https://www.objectos.com.br/blog/objectos-weekly-003.html#the-qualified-superclass-constructor-invocation). The main takeaway to remember is:

- in order to have an instance of the _inner class_ we must provide an instance of the _outer class_.

### Extending an inner class of `Super`

Let's say our superclass `Super` declares an inner class called `Inner`.

Let's have our `Example` class extend `Inner` instead of `Super`:

```java
package post;

public class Example extends post.util.Super.Inner {
  public Example(post.util.Super outer) {
    outer.super();
  }
}
```

As `Inner` is an inner class, we **must** provide an instance of `Super`. That is why we had to add the constructor and use the [qualified superclass constructor invocation](https://www.objectos.com.br/blog/objectos-weekly-003.html#the-qualified-superclass-constructor-invocation).

Let's get back to our hypothetical static analysis tool. Let's say we would like to:

- allow `null` values to the `Super` fields; but
- disallow `null` values to the `Inner` fields.

We can annotate our class like so:

```java
import post.annotation.NotNull;
import post.annotation.Nullable;

public class Example extends post.util.@Nullable Super.@NotNull Inner {
  public Example(post.util.Super outer) {
    outer.super();
  }
}
```

That's peculiar. I can definitely say I don't see it everyday.

It compiles without errors:

```
$ javac -d /tmp src/main/java/post/{,annotation,util}/*.java

[no errors emitted]
```

## Objectos Code Weekly

Work on Objectos Code is still in progress. Please note that the syntax is still subject to change. In fact I experimented a bit with names that are reserved keywords.

For instance, to write a package declaration in Objectos you write:

```java
_package("com.example.model");
```

As `package` is a reserved keyword, the name of the method has a leading _underscore_ character. I tried the following variations:

```java
packageDeclaration("com.example.model");

packageDecl("com.example.model");

package_("com.example.model");

package$("com.example.model");
```

But I was not pleased with any of them. So I decided to stick with the leading _underscore_ version.

### Method type parameters and type variables

You can declare a method with type parameters. The following Objectos Code:

```java
public class TypeParams extends JavaTemplate {
  @Override
  protected final void definition() {
    _package("objectos.example");

    autoImports();

    _class(
      _public(), _final(), id("Util"),

      constructor(_private()),

      method(
        _public(), _static(),
        tparam("T", t("com.example", "Foo")),
        _void(),
        id("sort"),
        param(t(t("java.util", "List"), tvar("T")), id("list")),

        invoke(t(Collections.class), "sort", n("list"))
      )
    );
  }
}
```

Generates:

```java
package objectos.example;

import com.example.Foo;
import java.util.Collections;
import java.util.List;

public final class Util {
  private Util() {}

  public static <T extends Foo> void sort(List<T> list) {
    Collections.sort(list);
  }
}
```

### Parameterized types

You might have noticed in the previous example that you can write type arguments of a generic type. The following Objectos Code:

```java
public class ParameterizedTypes extends JavaTemplate {
  @Override
  protected final void definition() {
    _package("objectos.example");

    autoImports();

    _class(
      _public(), id("ParameterizedTypesExample"),
    
      field(
        t(t("java.util", "Map"), t(String.class), t("java.lang", "Integer")),
        id("map")
      ),

      field(t(t(Set.class), t(OpenOption.class)), id("set")),

      field(
        t(
          t("java.util", "List"),
          t(t(Map.class), t(String.class), t(String.class))
        ), id("list")
      )
    );
  }
}
```

Generates:

```java
package objectos.example;

import java.nio.file.OpenOption;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ParameterizedTypesExample {
  Map<String, Integer> map;

  Set<OpenOption> set;

  List<Map<String, String>> list;
}
```

## Until the next issue of Objectos Weekly

So that's it for today. I hope you've enjoyed reading.

The source code of all of the examples are in this [GitHub repository](https://github.com/objectos/blog-examples/tree/master/p024-ow-004/src/main/java). 

If you liked this content please consider [subscribing to the blog via email](https://www.objectos.com.br/blog/index.html).