I have cloned the Maven repository, set it to branch 4.0.x (the default is 3.9.10), ran mvn clean install, then mvn generate-sources so I could debug it in Intellij to see how it works. I quickly stumbled upon an interface named Lookup, implemented in the ProtoLookup class that sits in package org.apache.maven.cling.invoker in the maven-cli module in the impl module. So far for nested modules and large codebases.

The ProtoLookup class has one member field that puzzled me:

private final Map<Class<?>, Object> components;

The puzzling thing is the Class<?> type that is used as key for this map. I never used Class<?> as type, it is new for me.

Reflection and creating Class<T> object

As I never worked with Class<T> and as it is no part of SE 11 I had no understanding of its use. So I asked ChatGPT who told me that:

  • This class is part of the Java Reflection API
  • This API is used to inspect and manipulate classes, fields and methods at runtime
  • An instance of Class<T> is return type of:
    • MyClass.class
    • someObject.getClass()
    • Class.forName(“fully.qualified.ClassName”)

General use

You can do the following things with it:

  • dynamically create objects
  • check types at runtime
  • look up methods, fields and annotations
  • register or reference types without instantiating them

Dynamically creating objects

There are two ways to create objects from a Class<T> object:

  • clazz.newInstance()
  • clazz.getDeclaredConstructor().newInstance()

Use in Maven

Maven uses class objects as keys in a registry map that is a member field of the ProtoLookup class. As keys must be unique, such a registry map must have unique object types in it and that is indeed the case here. Like many Maven types ProtoLookup has a public static Builder class inside that is used to create a ProtoLookup object and to add objects to the map, and this is the declaration/initialization of the map within that Builder class:

private final Map<Class<?>, Object> components = new HashMap<>();

The reason why this is a fine way of storing unique objects of different complex types, is that when you would use some other key type, you would have a bigger chance of doing the wrong casting when retrieving the element. Using Class<?> as key means you know by definition what the type of the object is. You can just ask for the “SettingsXmlConfigurationProcessor” key/type or the “CliRequest” key/type. It is all more type safe.


<
Previous Post
Maven Core class descriptions
>
Next Post
Intellij smart step debugging