Following library is used

  • Java 17
  • Micronaut 4.7.6

Sample code

A REST service which returns the current time in JSON format.

ApplicationDateTimeService

package example.micronaut;

import java.time.LocalDateTime;

public interface ApplicationDateTimeService {
    LocalDateTime getCurrentLocalDateTime();
}

ApplicationDateTimeServiceImpl

package example.micronaut;

import jakarta.inject.Singleton;
import java.time.LocalDateTime;

@Singleton
public class ApplicationDateTimeServiceImpl implements ApplicationDateTimeService {
    @Override
    public LocalDateTime getCurrentLocalDateTime() {
        return LocalDateTime.now();
    }
}

IndexController

package example.micronaut;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;
import jakarta.inject.Inject;
import java.time.format.DateTimeFormatter;

@Controller
public class IndexController {
    private final ApplicationDateTimeService service;
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");

    @Inject
    public IndexController(ApplicationDateTimeService service) {
        this.service = service;
    }

    @Produces(MediaType.APPLICATION_JSON)
    @Get
    public HttpResponse<Message> index() {
        return HttpResponse.ok(new Message(service.getCurrentLocalDateTime().format(formatter)));
    }
}

Message

package example.micronaut;

import io.micronaut.serde.annotation.Serdeable;

@Serdeable
public class Message {
    private final String message;

    public Message(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

Synthetic classes for dependency injection

After the project is compiled, following synthetic classes are generated. And they are extended from io.micronaut.context.AbstractInitializableBeanDefinitionAndReference.

Bean class Synthetic class
ApplicationDateTimeServiceImpl $ApplicationDateTimeServiceImpl$Definition
IndexController $IndexController$Definition

These classes contain information of bean classes, as well as the code that instantiates those beans.

$ApplicationDateTimeServiceImpl$Definition

package example.micronaut;

import io.micronaut.context.AbstractInitializableBeanDefinition;
import io.micronaut.context.AbstractInitializableBeanDefinitionAndReference;
import io.micronaut.context.BeanContext;
import io.micronaut.context.BeanResolutionContext;
import io.micronaut.context.condition.Condition;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Generated;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.ExecutableMethodsDefinition;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import java.util.List;
import java.util.Map;
import java.util.Optional;

// $FF: synthetic class
@Generated(
    service = "io.micronaut.inject.BeanDefinitionReference"
)
public class $ApplicationDateTimeServiceImpl$Definition extends AbstractInitializableBeanDefinitionAndReference<ApplicationDateTimeServiceImpl> {
    public static final AnnotationMetadata $ANNOTATION_METADATA = new DefaultAnnotationMetadata(Map.of("jakarta.inject.Singleton", Map.of()), Map.of("jakarta.inject.Scope", Map.of()), Map.of("jakarta.inject.Scope", Map.of()), Map.of("jakarta.inject.Singleton", Map.of()), Map.of("jakarta.inject.Scope", List.of("jakarta.inject.Singleton")), false, false);
    private static final Throwable $FAILURE;
    private static final AbstractInitializableBeanDefinition.MethodOrFieldReference $CONSTRUCTOR;
    private static final AbstractInitializableBeanDefinition.PrecalculatedInfo $INFO;

    public ApplicationDateTimeServiceImpl instantiate(BeanResolutionContext var1, BeanContext var2) {
        ApplicationDateTimeServiceImpl var3 = new ApplicationDateTimeServiceImpl();
        var3 = (ApplicationDateTimeServiceImpl)this.inject(var1, var2, var3);
        return var3;
    }

    public Object inject(BeanResolutionContext var1, BeanContext var2, Object var3) {
        ApplicationDateTimeServiceImpl var4 = (ApplicationDateTimeServiceImpl)var3;
        return super.inject(var1, var2, var3);
    }

    static {
        try {
            $CONSTRUCTOR = new AbstractInitializableBeanDefinition.MethodReference(ApplicationDateTimeServiceImpl.class, "", (Argument[])null, (AnnotationMetadata)null);
        } catch (Throwable var0) {
            $FAILURE = var0;
            $CONSTRUCTOR = null;
        }

        $INFO = new AbstractInitializableBeanDefinition.PrecalculatedInfo(Optional.of("jakarta.inject.Singleton"), false, false, true, false, false, false, false, false);
    }

    public $ApplicationDateTimeServiceImpl$Definition() {
        this(ApplicationDateTimeServiceImpl.class, $CONSTRUCTOR);
    }

    protected $ApplicationDateTimeServiceImpl$Definition(Class var1, AbstractInitializableBeanDefinition.MethodOrFieldReference var2) {
        super(var1, var2, $ANNOTATION_METADATA, (AbstractInitializableBeanDefinition.MethodReference[])null, (AbstractInitializableBeanDefinition.FieldReference[])null, (AbstractInitializableBeanDefinition.AnnotationReference[])null, (ExecutableMethodsDefinition)null, (Map)null, $INFO, new Condition[0], new Condition[0], $FAILURE);
    }

    public BeanDefinition load() {
        return new $ApplicationDateTimeServiceImpl$Definition();
    }

    public boolean isEnabled(BeanContext var1) {
        return true;
    }

    public boolean isEnabled(BeanContext var1, BeanResolutionContext var2) {
        return true;
    }
}

$IndexController$Definition

package example.micronaut;

import io.micronaut.context.AbstractInitializableBeanDefinition;
import io.micronaut.context.AbstractInitializableBeanDefinitionAndReference;
import io.micronaut.context.BeanContext;
import io.micronaut.context.BeanResolutionContext;
import io.micronaut.context.Qualifier;
import io.micronaut.context.condition.Condition;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Generated;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import java.util.List;
import java.util.Map;
import java.util.Optional;

// $FF: synthetic class
@Generated(
    service = "io.micronaut.inject.BeanDefinitionReference"
)
public class $IndexController$Definition extends AbstractInitializableBeanDefinitionAndReference<IndexController> {
    public static final AnnotationMetadata $ANNOTATION_METADATA = new DefaultAnnotationMetadata(Map.of("io.micronaut.http.annotation.Controller", Map.of(), "jakarta.inject.Singleton", Map.of()), Map.of("io.micronaut.context.annotation.Bean", Map.of(), "io.micronaut.context.annotation.DefaultScope", Map.of("value", $micronaut_load_class_value_0())), Map.of("io.micronaut.context.annotation.Bean", Map.of(), "io.micronaut.context.annotation.DefaultScope", Map.of("value", $micronaut_load_class_value_0())), Map.of("io.micronaut.http.annotation.Controller", Map.of(), "jakarta.inject.Singleton", Map.of()), Map.of("io.micronaut.context.annotation.Bean", List.of("io.micronaut.http.annotation.Controller"), "io.micronaut.context.annotation.DefaultScope", List.of("io.micronaut.http.annotation.Controller")), false, false);
    private static final Throwable $FAILURE;
    private static final AbstractInitializableBeanDefinition.MethodOrFieldReference $CONSTRUCTOR;
    private static final $IndexController$Definition$Exec $EXEC;
    private static final AbstractInitializableBeanDefinition.PrecalculatedInfo $INFO;

    public IndexController instantiate(BeanResolutionContext var1, BeanContext var2) {
        IndexController var3 = new IndexController((ApplicationDateTimeService)super.getBeanForConstructorArgument(var1, var2, 0, (Qualifier)null));
        var3 = (IndexController)this.inject(var1, var2, var3);
        return var3;
    }

    public Object inject(BeanResolutionContext var1, BeanContext var2, Object var3) {
        IndexController var4 = (IndexController)var3;
        return super.inject(var1, var2, var3);
    }

    static {
        try {
            $CONSTRUCTOR = new AbstractInitializableBeanDefinition.MethodReference(IndexController.class, "", new Argument[]{Argument.of(ApplicationDateTimeService.class, "service")}, new DefaultAnnotationMetadata(Map.of("jakarta.inject.Inject", Map.of()), Map.of(), Map.of(), Map.of("jakarta.inject.Inject", Map.of()), Map.of(), false, false));
            $EXEC = new $IndexController$Definition$Exec();
        } catch (Throwable var0) {
            $FAILURE = var0;
            $CONSTRUCTOR = null;
            $EXEC = null;
        }

        $INFO = new AbstractInitializableBeanDefinition.PrecalculatedInfo(Optional.empty(), false, false, true, false, false, false, false, false);
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_1(), Map.of("consumes", new String[]{"application/json"}, "produces", new String[]{"application/json"}, "value", "/"));
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_2(), Map.of("single", false, "value", new String[]{"application/json"}));
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_3(), Map.of("consumes", new String[0], "headRoute", true, "processes", new String[0], "produces", new String[0], "single", false, "uri", "/", "uris", new String[]{"/"}, "value", "/"));
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_4(), Map.of("uris", new String[]{"/"}, "value", "/"));
        DefaultAnnotationMetadata.registerAnnotationType($micronaut_load_class_value_5());
    }

    public $IndexController$Definition() {
        this(IndexController.class, $CONSTRUCTOR);
    }

    protected $IndexController$Definition(Class var1, AbstractInitializableBeanDefinition.MethodOrFieldReference var2) {
        super(var1, var2, $ANNOTATION_METADATA, (AbstractInitializableBeanDefinition.MethodReference[])null, (AbstractInitializableBeanDefinition.FieldReference[])null, (AbstractInitializableBeanDefinition.AnnotationReference[])null, $EXEC, (Map)null, $INFO, new Condition[0], new Condition[0], $FAILURE);
    }

    public BeanDefinition load() {
        return new $IndexController$Definition();
    }

    public boolean isEnabled(BeanContext var1) {
        return true;
    }

    public boolean isEnabled(BeanContext var1, BeanResolutionContext var2) {
        return true;
    }
}

Following empty files are created.

  • META-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/example.micronaut.$ApplicationDateTimeServiceImpl$Definition
  • META-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/example.micronaut.$IndexController$Definition

Synthetic classes for avoid using Java Reflection API

Following synthetic class is generated also after compilation. And it is extended from io.micronaut.context.AbstractExecutableMethodsDefinition.

Bean class Synthetic class
IndexController $IndexController$Definition$Exec

Methods of a REST controller are normally called by the http server library by using Java Reflection API. Code in synthetic class performs the same function which Java Reflection API does.

$IndexController$Definition$Exec

package example.micronaut;

import example.micronaut..IndexController.Definition;
import io.micronaut.context.AbstractExecutableMethodsDefinition;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Generated;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.type.Argument;
import io.micronaut.http.HttpResponse;
import io.micronaut.inject.annotation.AnnotationMetadataHierarchy;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

// $FF: synthetic class
@Generated
final class $IndexController$Definition$Exec extends AbstractExecutableMethodsDefinition {
    private static final AbstractExecutableMethodsDefinition.MethodReference[] $METHODS_REFERENCES = new AbstractExecutableMethodsDefinition.MethodReference[]{$metadata$index()};

    private static final AbstractExecutableMethodsDefinition.MethodReference $metadata$index() {
        return new AbstractExecutableMethodsDefinition.MethodReference(IndexController.class, new AnnotationMetadataHierarchy(new AnnotationMetadata[]{Definition.$ANNOTATION_METADATA, new DefaultAnnotationMetadata(Map.of("io.micronaut.http.annotation.Get", Map.of(), "io.micronaut.http.annotation.Produces", Map.of("value", new String[]{"application/json"})), Map.of("io.micronaut.context.annotation.Executable", Map.of(), "io.micronaut.core.annotation.EntryPoint", Map.of(), "io.micronaut.http.annotation.HttpMethodMapping", Map.of()), Map.of("io.micronaut.context.annotation.Executable", Map.of(), "io.micronaut.core.annotation.EntryPoint", Map.of(), "io.micronaut.http.annotation.HttpMethodMapping", Map.of()), Map.of("io.micronaut.http.annotation.Get", Map.of(), "io.micronaut.http.annotation.Produces", Map.of("value", new String[]{"application/json"})), Map.of("io.micronaut.context.annotation.Executable", List.of("io.micronaut.http.annotation.HttpMethodMapping"), "io.micronaut.core.annotation.EntryPoint", List.of("io.micronaut.http.annotation.HttpMethodMapping"), "io.micronaut.http.annotation.HttpMethodMapping", List.of("io.micronaut.http.annotation.Get")), false, false)}), "index", Argument.of(HttpResponse.class, "io.micronaut.http.HttpResponse", (AnnotationMetadata)null, new Argument[]{Argument.of(Message.class, "B")}), (Argument[])null, false, false);
    }

    public $IndexController$Definition$Exec() {
        super($METHODS_REFERENCES);
    }

    protected final Object dispatch(int var1, Object var2, Object[] var3) {
        switch (var1) {
            case 0 -> {
                return ((IndexController)var2).index();
            }
            default -> throw this.unknownDispatchAtIndexException(var1);
        }
    }

    protected final Method getTargetMethodByIndex(int var1) {
        switch (var1) {
            case 0 -> {
                return ReflectionUtils.getRequiredMethod(IndexController.class, "index", ReflectionUtils.EMPTY_CLASS_ARRAY);
            }
            default -> throw this.unknownDispatchAtIndexException(var1);
        }
    }
}

Synthetic classes for JSON serialization/deserialization

Following synthetic class is generated also after compilation. And it is extended from io.micronaut.inject.beans.AbstractInitializableBeanIntrospectionAndReference.

Class Synthetic class
Message $Message$Introspection

JSON serialization/deserialization libraries are also heavily relied on Java Reflection API. Code in synthetic class performs JSON serialization/deserialization.

$Message$Introspection

package example.micronaut;

import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Generated;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.type.Argument;
import io.micronaut.inject.annotation.DefaultAnnotationMetadata;
import io.micronaut.inject.beans.AbstractInitializableBeanIntrospection;
import io.micronaut.inject.beans.AbstractInitializableBeanIntrospectionAndReference;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

// $FF: synthetic class
@Generated(
    service = "example.micronaut.$Message$Introspection"
)
public final class $Message$Introspection extends AbstractInitializableBeanIntrospectionAndReference {
    private static final Argument[] $CONSTRUCTOR_ARGUMENTS = new Argument[]{Argument.of(String.class, "message")};
    private static final AbstractInitializableBeanIntrospection.BeanPropertyRef[] $PROPERTIES_REFERENCES;
    public static final AnnotationMetadata $ANNOTATION_METADATA;

    static {
        AbstractInitializableBeanIntrospection.BeanPropertyRef[] var10000 = new AbstractInitializableBeanIntrospection.BeanPropertyRef[1];
        Argument var0 = Argument.of(String.class, "message");
        var10000[0] = new AbstractInitializableBeanIntrospection.BeanPropertyRef(var0, var0, (Argument)null, 0, -1, 1, true, true);
        $PROPERTIES_REFERENCES = var10000;
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_0(), Map.of("naming", $micronaut_load_class_value_1(), "validate", true));
        DefaultAnnotationMetadata.registerAnnotationType($micronaut_load_class_value_2());
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_3(), Map.of("as", $micronaut_load_class_value_4(), "naming", $micronaut_load_class_value_1(), "using", $micronaut_load_class_value_5(), "validate", true));
        DefaultAnnotationMetadata.registerAnnotationDefaults($micronaut_load_class_value_6(), Map.of("as", $micronaut_load_class_value_4(), "naming", $micronaut_load_class_value_1(), "using", $micronaut_load_class_value_7(), "validate", true));
        $ANNOTATION_METADATA = new DefaultAnnotationMetadata(Map.of("io.micronaut.serde.annotation.Serdeable", Map.of()), Map.of("io.micronaut.core.annotation.Internal", Map.of(), "io.micronaut.core.annotation.Introspected", Map.of(), "io.micronaut.serde.annotation.Serdeable$Deserializable", Map.of(), "io.micronaut.serde.annotation.Serdeable$Serializable", Map.of(), "io.micronaut.serde.config.annotation.SerdeConfig", Map.of()), Map.of("io.micronaut.core.annotation.Internal", Map.of(), "io.micronaut.core.annotation.Introspected", Map.of(), "io.micronaut.serde.annotation.Serdeable$Deserializable", Map.of(), "io.micronaut.serde.annotation.Serdeable$Serializable", Map.of(), "io.micronaut.serde.config.annotation.SerdeConfig", Map.of()), Map.of("io.micronaut.serde.annotation.Serdeable", Map.of()), Map.of("io.micronaut.core.annotation.Internal", List.of("io.micronaut.serde.config.annotation.SerdeConfig"), "io.micronaut.core.annotation.Introspected", List.of("io.micronaut.serde.annotation.Serdeable", "io.micronaut.serde.annotation.Serdeable$Serializable", "io.micronaut.serde.annotation.Serdeable$Deserializable"), "io.micronaut.serde.annotation.Serdeable$Deserializable", List.of("io.micronaut.serde.annotation.Serdeable"), "io.micronaut.serde.annotation.Serdeable$Serializable", List.of("io.micronaut.serde.annotation.Serdeable"), "io.micronaut.serde.config.annotation.SerdeConfig", List.of("io.micronaut.serde.annotation.Serdeable", "io.micronaut.serde.annotation.Serdeable$Serializable", "io.micronaut.serde.annotation.Serdeable$Deserializable")), false, false);
    }

    public $Message$Introspection() {
        super(Message.class, $ANNOTATION_METADATA, (AnnotationMetadata)null, $CONSTRUCTOR_ARGUMENTS, $PROPERTIES_REFERENCES, (AbstractInitializableBeanIntrospection.BeanMethodRef[])null);
    }

    protected final Object dispatchOne(int var1, Object var2, Object var3) {
        switch (var1) {
            case 0:
                return ((Message)var2).getMessage();
            case 1:
                Message var4 = (Message)var2;
                return new Message((String)var3);
            default:
                throw this.unknownDispatchAtIndexException(var1);
        }
    }

    protected final Method getTargetMethodByIndex(int var1) {
        switch (var1) {
            case 0 -> {
                return ReflectionUtils.getRequiredMethod(Message.class, "getMessage", ReflectionUtils.EMPTY_CLASS_ARRAY);
            }
            default -> throw this.unknownDispatchAtIndexException(var1);
        }
    }

    public final boolean hasConstructor() {
        return true;
    }

    public Object instantiateInternal(Object[] var1) {
        return new Message((String)var1[0]);
    }

    public final boolean isBuildable() {
        return true;
    }

    public final boolean hasBuilder() {
        return false;
    }
}

Following empty files are created.

  • META-INF/micronaut/io.micronaut.core.beans.BeanIntrospectionReference/example.micronaut.$Message$Introspection

Java compiler processor

In micronaut-inject-java-4.7.14.jar file, it contains following classes which implement javax.annotation.processing.Processor interface for generating synthetic classes.

  • io.micronaut.annotation.processing.BeanDefinitionInjectProcessor
  • io.micronaut.annotation.processing.ConfigurationMetadataProcessor
  • io.micronaut.annotation.processing.PackageConfigurationInjectProcessor
  • io.micronaut.annotation.processing.TypeElementVisitorProcessor
  • io.micronaut.annotation.processing.AggregatingTypeElementVisitorProcessor

And micronaut-http-validation-4.7.14.jar, micronaut-security-annotations-4.11.3.jar and micronaut-serde-processor-2.12.1.jar files contain classes for scanning annotations which are interesting.