Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use official Maven image with Eclipse Temurin Java 25
FROM maven:3.9.11-eclipse-temurin-25
# Use official Maven image with Eclipse Temurin Java 21 LTS
FROM maven:3.9.11-eclipse-temurin-21

# Install unzip, zsh and other tools needed
RUN apt-get update && apt-get install -y \
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:
<dependency>
<groupId>com.github.wassertim</groupId>
<artifactId>dynamodb-toolkit</artifactId>
<version>v${{ env.NEW_VERSION }}</version>
<version>${{ env.NEW_VERSION }}</version>
</dependency>
```

Expand Down Expand Up @@ -186,7 +186,7 @@ jobs:

# Now that JitPack succeeded, update README with new version
echo "πŸ“ Updating README.md with confirmed working version..."
sed -i "s/<version>v[^<]*<\/version>/<version>v$NEW_VERSION<\/version>/" README.md
sed -i "s/<version>[^<]*<\/version>/<version>$NEW_VERSION<\/version>/" README.md

# Check if README actually changed
if git diff --quiet README.md; then
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Add the JitPack repository and dependency to your Maven build:
<dependency>
<groupId>com.github.wassertim</groupId>
<artifactId>dynamodb-toolkit</artifactId>
<version>v1.0.0</version>
<version>1.0.0</version>
</dependency>
```

Expand Down
125 changes: 125 additions & 0 deletions docs/JAVAPOET_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# JavaPoet Migration Performance Analysis

## Overview

The DynamoDB Toolkit has been successfully migrated from string-based code generation to JavaPoet-based code generation. This migration improves code quality, maintainability, and type safety while maintaining all existing functionality.

## Performance Metrics

### Generated Code Quality

**TestUserMapper Analysis:**
- **Total Lines:** 226 lines
- **File Size:** 12KB
- **Import Statements:** 10 imports
- **Methods Generated:** 6 (2 core + 4 convenience methods)

### Code Quality Improvements

1. **Type Safety**
- Eliminated string concatenation artifacts
- No escaped newlines (`\\n`) in generated code
- No `PrintWriter.println()` artifacts
- Proper use of `CodeBlock` for structured code generation

2. **Modern Java Syntax**
- Switch expressions instead of traditional switch statements
- Proper use of `var` for type inference
- Clean method chaining patterns

3. **Import Optimization**
- JavaPoet automatically optimizes imports
- Only necessary imports are included
- Consistent import ordering

4. **Code Formatting**
- Consistent 4-space indentation
- Proper JavaDoc documentation
- Clean null handling patterns

## Validation Results

All 7 JavaPoet validation tests pass successfully:

### βœ… TestUserMapper Quality Validation
- Contains required annotations (`@ApplicationScoped`)
- Includes all core mapping methods
- No string concatenation artifacts
- Proper JavaDoc with generation timestamps

### βœ… TestUserFields Quality Validation
- Proper utility class structure
- Type-safe field constants
- Prevents instantiation with private constructor
- Comprehensive field documentation

### βœ… TableNameResolver Quality Validation
- Modern switch expression syntax
- No old-style switch breaks
- Proper error handling with detailed messages
- Lists all known table mappings

### βœ… Performance Metrics
- Mapper LOC within optimal range (150-300 lines)
- Import count optimized (<15 imports)
- Reasonable file sizes (5-15KB for mappers, 1-5KB for fields)
- 6 methods generated as expected

### βœ… Code Consistency
- 4-space indentation throughout
- Consistent null handling patterns
- Uniform naming conventions for all methods

### βœ… Compilation Performance
- Test execution completes in <1 second
- No significant compilation overhead
- Memory efficient code generation

### βœ… Generated Code Size Validation
- Mapper files: 5-15KB (actual: 12KB)
- Field files: 1-5KB (within range)
- No unnecessary code bloat

## Migration Benefits

### 1. **Maintainability**
- Type-safe code generation APIs
- Compile-time validation of generated code structure
- Easier to extend with new mapping strategies
- Clear separation of concerns in code generators

### 2. **Code Quality**
- Consistent formatting and structure
- Automatic import optimization
- Modern Java syntax patterns
- No string manipulation artifacts

### 3. **Developer Experience**
- Better IDE support for code generators
- Type-safe method calls and parameters
- Easier debugging of code generation logic
- Clear error messages during annotation processing

### 4. **Performance**
- No runtime overhead changes
- Optimized generated code structure
- Minimal memory footprint
- Fast compilation and code generation

## Integration Test Results

All existing integration tests continue to pass:
- `MappingUtilsTest`: Runtime utilities validation
- `GeneratedMapperTest`: End-to-end mapping functionality
- Domain object serialization/deserialization
- Complex nested object handling

## Conclusion

The JavaPoet migration successfully modernizes the code generation infrastructure while maintaining 100% backward compatibility. The generated code is higher quality, more maintainable, and follows modern Java best practices. All performance metrics are within optimal ranges, and comprehensive validation ensures continued reliability.

**Migration Status: βœ… COMPLETE**
- Code generation: βœ… Migrated to JavaPoet
- Testing: βœ… All tests passing
- Performance: βœ… Validated and optimal
- Documentation: βœ… Complete
5 changes: 5 additions & 0 deletions integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
<artifactId>dynamodb-toolkit</artifactId>
<version>${dynamodb-toolkit.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Expand Down
25 changes: 25 additions & 0 deletions integration-tests/src/main/java/com/tourino/domain/Difficulty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.tourino.domain;

/**
* Enumeration of route difficulty levels for user classification.
*/
public enum Difficulty {
EASY("Easy - suitable for beginners"),
MODERATE("Moderate - some experience required"),
HARD("Hard - experienced users only"),
EXPERT("Expert - professional level");

private final String description;

Difficulty(String description) {
this.description = description;
}

/**
* Gets the human-readable description of this difficulty level.
* @return the difficulty description
*/
public String getDescription() {
return description;
}
}
101 changes: 101 additions & 0 deletions integration-tests/src/main/java/com/tourino/domain/Route.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.tourino.domain;

import com.github.wassertim.dynamodb.toolkit.api.annotations.AttributeType;
import com.github.wassertim.dynamodb.toolkit.api.annotations.PartitionKey;
import com.github.wassertim.dynamodb.toolkit.api.annotations.SortKey;
import com.github.wassertim.dynamodb.toolkit.api.annotations.Table;
import com.github.wassertim.dynamodb.toolkit.api.annotations.DynamoMappable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.Instant;
import java.util.List;

/**
* Main user route entity for persistent route management.
* Represents a user's saved route with full lifecycle support and rich metadata.
*/
@DynamoMappable
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Table(name = "routes")
public class Route {

/**
* User ID - partition key for data isolation and efficient queries.
*/
@PartitionKey(attributeType = AttributeType.STRING)
private String userId;

/**
* Unique route identifier - UUID for global uniqueness.
*/
@SortKey(attributeType = AttributeType.STRING)
private String routeId;

/**
* User-defined route name (3-100 characters).
*/
private String name;

/**
* Optional description providing additional context about the route.
*/
private String description;

/**
* Route type classification for filtering and organization.
*/
private RouteType type;

/**
* Difficulty level assessment for user guidance.
*/
private Difficulty difficulty;

/**
* The routing profile used for route calculation (e.g., "cycling-regular", "walking", "driving-car").
* This preserves the exact calculation parameters used and ensures route consistency.
*/
private String routingProfile;

/**
* Ordered collection of waypoints defining the route path.
*/
private List<Waypoint> waypoints;

/**
* Route geometry containing path coordinates and shape data.
*/
private RouteGeometry routeGeometry;

/**
* Calculated route statistics and measurements.
*/
private RouteMetadata metadata;


/**
* Route creation timestamp for audit trail.
*/
private Instant createdAt;

/**
* Last modification timestamp for change tracking.
*/
private Instant updatedAt;

/**
* Last accessed timestamp for usage analytics and recent route queries.
*/
private Instant lastUsed;

/**
* User-defined tags for route categorization and search.
*/
private List<String> tags;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.tourino.domain;

import com.tourino.domain.enums.GeometryType;
import com.github.wassertim.dynamodb.toolkit.api.annotations.DynamoMappable;
import lombok.Builder;
import lombok.Data;

import java.util.List;

/**
* Domain value object representing route geometry as GeoJSON LineString.
*/
@DynamoMappable
@Data
@Builder
public class RouteGeometry {

/**
* GeoJSON type (always LINESTRING for routes).
*/
@Builder.Default
private final GeometryType type = GeometryType.LINESTRING;

/**
* Array of coordinate pairs [longitude, latitude] defining the route path.
*/
private final List<List<Double>> coordinates;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.tourino.domain;

import com.github.wassertim.dynamodb.toolkit.api.annotations.DynamoMappable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* Value object containing route calculation metadata and statistics.
* Stores numeric values for calculations, not formatted strings.
*/
@DynamoMappable
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RouteMetadata {

/**
* Total route distance in meters.
*/
private Double distance;

/**
* Total route duration in seconds.
*/
private Double duration;

/**
* Total elevation gain in meters.
*/
private Double elevationGain;

/**
* Total elevation loss in meters.
*/
private Double elevationLoss;

/**
* Minimum elevation in meters.
*/
private Double minElevation;

/**
* Maximum elevation in meters.
*/
private Double maxElevation;

/**
* Average speed in kilometers per hour.
*/
private Double averageSpeed;
}
Loading