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.