Skip to content

Commit

Permalink
Add Jandex based registry for serialized data types
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-schnell committed Jan 21, 2024
1 parent 0a7cfb7 commit e1fbf23
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 4 deletions.
11 changes: 8 additions & 3 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@
<artifactId>jakarta.json-api</artifactId>
</dependency>

<!-- test -->

<dependency>
<groupId>io.smallrye</groupId>
<artifactId>jandex</artifactId>
<scope>test</scope>
</dependency>

<!-- test -->

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down Expand Up @@ -137,6 +136,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static SerializedDataType extractValue(final Class<?> clasz, final String
if (result.message() == null) {
return (SerializedDataType) result.value();
}
throw new IllegalArgumentException(result.message());
throw new IllegalArgumentException(result.message() + " (" + clasz + ")");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.fuin.esc.api;

import jakarta.validation.constraints.NotNull;
import org.fuin.utils4j.JandexIndexFileReader;
import org.fuin.utils4j.JandexUtils;
import org.jboss.jandex.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Modifier;
import java.util.*;

/**
* Registry that is built up by scanning for classes that are annotated with {@link HasSerializedDataTypeConstant}.
* Inner classes are ignored.
*/
public class JandexSerializedDataTypeRegistry implements SerializedDataTypeRegistry {

private static final Logger LOG = LoggerFactory.getLogger(JandexSerializedDataTypeRegistry.class);

private final SimpleSerializedDataTypeRegistry delegate;

private final List<File> classesDirs;

private final List<Class<?>> classes;

/**
* Default constructor.
*/
public JandexSerializedDataTypeRegistry() {
this(new File("target/classes"));
}

/**
* Constructor with classes directories. Most likely only used in tests.
*
* @param classesDirs Directories with class files.
*/
public JandexSerializedDataTypeRegistry(final File... classesDirs) {
delegate = new SimpleSerializedDataTypeRegistry();
this.classesDirs = Arrays.asList(classesDirs);
classes = scanForClasses();
for (final Class<?> domainEventClass : classes) {
delegate.add(serializedDataTypeConstant(domainEventClass), domainEventClass);
}
}

@Override
@NotNull
public Class<?> findClass(@NotNull SerializedDataType type) {
return delegate.findClass(type);
}

/**
* Returns a list of known classes that can be serialized.
*
* @return SerializedDataType classes.
*/
public List<Class<?>> getClasses() {
return Collections.unmodifiableList(classes);
}

private List<Class<?>> scanForClasses() {
final List<IndexView> indexes = new ArrayList<>();
indexes.add(new JandexIndexFileReader.Builder().addDefaultResource().build().loadR());
indexes.add(indexClassesDirs());
return findClasses(CompositeIndex.create(indexes));
}

private IndexView indexClassesDirs() {
final Indexer indexer = new Indexer();
final List<File> knownClassFiles = new ArrayList<>();
for (final File classesDir : classesDirs) {
JandexUtils.indexDir(indexer, knownClassFiles, classesDir);
}
return indexer.complete();
}

private static List<Class<?>> findClasses(final IndexView index) {
List<Class<?>> classes = new ArrayList<>();
final Collection<AnnotationInstance> annotationInstances = index.getAnnotations(DotName.createSimple(HasSerializedDataTypeConstant.class));
for (final AnnotationInstance annotationInstance : annotationInstances) {
final ClassInfo classInfo = annotationInstance.target().asClass();
if (!Modifier.isAbstract(classInfo.flags())
&& !Modifier.isInterface(classInfo.flags())
&& !classInfo.name().toString().contains("$")) {
final Class<?> clasz = JandexUtils.loadClass(classInfo.name());
classes.add(clasz);
LOG.info("Added SerializedDataType to {}: {}", JandexSerializedDataTypeRegistry.class.getSimpleName(), clasz.getName());
}
}
return classes;
}

public SerializedDataType serializedDataTypeConstant(Class<?> domainEventClass) {
final HasSerializedDataTypeConstant annotation = domainEventClass.getAnnotation(HasSerializedDataTypeConstant.class);
return HasSerializedDataTypeConstantValidator.extractValue(domainEventClass, annotation.value());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.fuin.esc.api;

import org.junit.jupiter.api.Test;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Test for the {@link JandexSerializedDataTypeRegistry} class.
*/
public class JandexSerializedDataTypeRegistryTest {

@Test
public void testCreate() {
final JandexSerializedDataTypeRegistry testee = new JandexSerializedDataTypeRegistry(new File("target/test-classes"));
assertThat(testee.getClasses()).containsOnly(MyEvent.class);
}

@Test
public void testFind() {
final JandexSerializedDataTypeRegistry testee = new JandexSerializedDataTypeRegistry(new File("target/test-classes"));
assertThat(testee.findClass(MyEvent.SER_TYPE)).isEqualTo(MyEvent.class);
}

}
3 changes: 3 additions & 0 deletions api/src/test/java/org/fuin/esc/api/MyEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
/**
* Example event.
*/
@HasSerializedDataTypeConstant
public class MyEvent {

public static final SerializedDataType SER_TYPE = new SerializedDataType("MyEvent");

private String name;

public MyEvent(final String name) {
Expand Down
18 changes: 18 additions & 0 deletions api/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{yyyy.dd.MM HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</encoder>
</appender>

<root level="info">
<appender-ref ref="CONSOLE" />
</root>

<!--
<logger name="org.fuin.esc" level="DEBUG"/>
-->

</configuration>
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@
<version>4.0.1</version>
</dependency>

<dependency>
<groupId>io.smallrye</groupId>
<artifactId>jandex</artifactId>
<version>3.1.2</version>
</dependency>

</dependencies>

</dependencyManagement>
Expand Down
1 change: 1 addition & 0 deletions spi/src/main/java/org/fuin/esc/spi/Base64Data.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
/**
* Contains some Base64 encoded data.
*/
@HasSerializedDataTypeConstant
@XmlRootElement(name = Base64Data.EL_ROOT_NAME)
public final class Base64Data implements ToJsonCapable {

Expand Down
1 change: 1 addition & 0 deletions spi/src/main/java/org/fuin/esc/spi/EscEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
/**
* An event structure.
*/
@HasSerializedDataTypeConstant
@XmlRootElement(name = EscEvent.EL_ROOT_NAME)
public final class EscEvent implements ToJsonCapable {

Expand Down
1 change: 1 addition & 0 deletions spi/src/main/java/org/fuin/esc/spi/EscEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
/**
* A list of events.
*/
@HasSerializedDataTypeConstant
@XmlRootElement(name = EscEvents.EL_ROOT_NAME)
public final class EscEvents implements ToJsonCapable {

Expand Down
1 change: 1 addition & 0 deletions spi/src/main/java/org/fuin/esc/spi/EscMeta.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
/**
* A structure that contains the user's meta data and the system's meta information.
*/
@HasSerializedDataTypeConstant
@XmlRootElement(name = EscMeta.EL_ROOT_NAME)
public final class EscMeta implements ToJsonCapable {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.fuin.esc.spi;

import org.fuin.esc.api.JandexSerializedDataTypeRegistry;
import org.junit.jupiter.api.Test;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Test for the {@link JandexSerializedDataTypeRegistry} class.
*/
public class JandexSerializedDataTypeRegistryTest {

@Test
public void testBaseDataTypes() {
final JandexSerializedDataTypeRegistry testee = new JandexSerializedDataTypeRegistry();
assertThat(testee.getClasses()).containsOnly(
Base64Data.class,
EscEvent.class,
EscEvents.class,
EscMeta.class
);
}

}

0 comments on commit e1fbf23

Please sign in to comment.