Essence of the Approach
My approach includes three steps:
Sample Classes with Annotations
Sample classes to demonstrate the approach
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record Author(String name) {
}
import java.time.LocalDateTime;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record Note(String title, Author author,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "UTC") //
@JsonSerialize(using = LocalDateTimeSerializer.class) //
@JsonDeserialize(using = LocalDateTimeDeserializer.class) //
LocalDateTime publicationDate, List<NoteTag> tags) {
}
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum NoteTag {
@JsonProperty("ELASTICSEARCH")
ELASTICSEARCH,
@JsonProperty("JAVA")
JAVA,
@JsonProperty("JSON")
JSON,
@JsonProperty("REST")
REST;
}
Methods Implementing the Approach
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
public class Runner {
public static Package[] getDeclaredPackages() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return classLoader.getDefinedPackages();
}
public static Collection<Class<?>> getPackageClasses(final String packageName)
throws Exception {
final StandardJavaFileManager fileManager = ToolProvider
.getSystemJavaCompiler()
.getStandardFileManager(null, null, null);
return StreamSupport
.stream(fileManager
.list(StandardLocation.CLASS_PATH, packageName,
Collections.singleton(
JavaFileObject.Kind.CLASS),
false)
.spliterator(), false)
.map(javaFileObject -> {
try {
final String canonicalClassName = javaFileObject
.getName().replaceAll("[\\\\/]", ".")
.replaceAll(
".*(" + packageName + ".*)\\.class.*",
"$1");
return Class.forName(canonicalClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toCollection(ArrayList::new));
}
public static void main(String[] args) throws Exception {
Field[] fields = Note.class.getDeclaredFields();
for (Field field : fields) {
Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
System.out.println(Arrays.toString(fieldAnnotations));
}
Package[] packages = getDeclaredPackages();
Collection<Class<?>> classes = new LinkedList<>();
for (Package packaje : packages) {
Collection<Class<?>> packageClasses = getPackageClasses(packaje.getName());
System.out.printf("Package '%s': %d class(es)\n", packaje.getName(),
packageClasses.size());
classes.addAll(packageClasses);
}
System.out.println();
classes.stream().filter(c -> (c.isAnnotationPresent(JsonNaming.class))).forEach(System.out::println);
}
}
Printing field annotations in the first lines of the main method is only for using annotations in program. Note is a sample class (listed above)
Loop for (Package packaje : packages) counts classes in every package and add them to the collection
Project uses libraries:
jackson-annotations-2.16.0.jar
jackson-core-2.16.0.jar
jackson-databind-2.16.0.jar
jackson-datatype-jsr310-2.12.3.jar
Output at the Console
Package 'com.fasterxml.jackson.annotation': 73 class(es)
Package 'com.fasterxml.jackson.databind.deser': 46 class(es)
Package 'com.fasterxml.jackson.datatype.jsr310.deser': 15 class(es)
Package 'com.fasterxml.jackson.databind.jsonFormatVisitors': 27 class(es)
Package 'g0l0s.annotatedclassretriever.entities': 3 class(es)
Package 'com.fasterxml.jackson.databind.util': 59 class(es)
Package 'com.fasterxml.jackson.databind.ser.std': 76 class(es)
Package 'com.fasterxml.jackson.databind.ser': 25 class(es)
Package 'com.fasterxml.jackson.databind.jsonschema': 4 class(es)
Package 'com.fasterxml.jackson.datatype.jsr310.ser': 17 class(es)
Package 'g0l0s.annotatedclassretriever': 1 class(es)
Package 'com.fasterxml.jackson.databind.annotation': 17 class(es)
Package 'com.fasterxml.jackson.databind': 73 class(es)
Package 'com.fasterxml.jackson.databind.deser.std': 90 class(es)
Classes with an annotation:
class g0l0s.annotatedclassretriever.entities.Author
class g0l0s.annotatedclassretriever.entities.Note
ServiceLoader(standard JDK); or a agent, seejava.lang.instrument