Skip to content

Commit 44ac70d

Browse files
authored
fix: prevent multi-round annotation processing bug (#7)
Fixes issue #6 where List<Integer> fields were incorrectly generating ListMapper dependencies due to multi-round annotation processing. Problem: - Annotation processor was running in multiple rounds - First round: Correct inline NUMBER_LIST mapping - Second round: Incorrect ListMapper dependency - Type information behaves differently in subsequent rounds Solution: - Track processed types to avoid reprocessing - Skip processing in subsequent rounds (processingOver, empty rootElements) - Only process in the first round for consistent type information - Add DEBUG_MARKER for build verification Testing: - Verified no ListMapper references in generated code - Confirmed inline NUMBER_LIST mapping for List<Integer> - Single timestamp showing processor runs only once Closes #6
1 parent 586525f commit 44ac70d

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

src/main/java/com/github/wassertim/dynamodb/toolkit/generation/MapperGenerator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ private TypeSpec buildMapperClass(TypeInfo typeInfo) {
5555
.addAnnotation(ApplicationScoped.class)
5656
.addJavadoc(createGeneratedJavadoc(
5757
"Generated DynamoDB mapper for " + className + ".\n" +
58-
"Provides bidirectional conversion between " + className + " and DynamoDB AttributeValue."
58+
"Provides bidirectional conversion between " + className + " and DynamoDB AttributeValue.\n" +
59+
"DEBUG_MARKER: Local build verification - " + System.currentTimeMillis()
5960
));
6061

6162
// Add dependency injection (fields and constructor)

src/main/java/com/github/wassertim/dynamodb/toolkit/processor/AnnotationProcessor.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public class AnnotationProcessor extends AbstractProcessor {
6161
private FieldConstantsGenerator fieldConstantsGenerator;
6262
private TableNameResolverGenerator tableNameResolverGenerator;
6363

64+
// Track processed types to avoid reprocessing in subsequent rounds
65+
private final Set<String> processedTypes = new java.util.HashSet<>();
66+
6467
@Override
6568
public synchronized void init(ProcessingEnvironment processingEnv) {
6669
super.init(processingEnv);
@@ -79,17 +82,40 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
7982

8083
@Override
8184
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
85+
// Skip processing if annotations are empty
8286
if (annotations.isEmpty()) {
8387
return false;
8488
}
8589

90+
// CRITICAL FIX: Only process in the first round, skip all subsequent rounds
91+
// This prevents multi-round processing bugs where type information changes between rounds
92+
if (!roundEnv.processingOver() && roundEnv.getRootElements().isEmpty()) {
93+
// This is a subsequent round with no new source files - skip it
94+
return false;
95+
}
96+
97+
// Skip the final processing-over round
98+
if (roundEnv.processingOver()) {
99+
return false;
100+
}
101+
102+
// Only process if we haven't processed anything yet (first round only)
103+
if (!processedTypes.isEmpty()) {
104+
return false;
105+
}
106+
86107
try {
87108
// Collect all @DynamoMappable annotated elements
88109
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(DynamoMappable.class);
89110

90111
// Collect all @Table annotated elements
91112
Set<? extends Element> tableElements = roundEnv.getElementsAnnotatedWith(Table.class);
92113

114+
// Mark all types as processed
115+
for (Element element : annotatedElements) {
116+
processedTypes.add(((TypeElement) element).getQualifiedName().toString());
117+
}
118+
93119
// If no annotations to process, return false
94120
if (annotatedElements.isEmpty() && tableElements.isEmpty()) {
95121
return false;

0 commit comments

Comments
 (0)