A Java application for validating and comparing menu JSON documents from AWS S3, supporting both Spotlight and Digital Communications menu formats.
- Multi-Format Support: Validates both Spotlight and Digital Communications board menus
- Deep Comparison: Performs recursive field-by-field comparison to detect differences
- Hash-Based Optimization: Skips comparison if menu hash codes match
- AWS S3 Integration: Fetch menu JSON files directly from S3 buckets
- Comprehensive Logging: Detailed logging of validation results and differences
- Flexible Models: Lombok-powered models supporting multiple menu types
- Java 21 (LTS)
- Spring Boot 3.4.3
- Jackson 2.15+ - JSON processing
- Lombok 1.18.30 - Boilerplate reduction
- AWS SDK 2.20.26 - S3 integration
- Gradle 8.14 - Build automation
- JUnit 5 & AssertJ - Testing
src/
├── main/java/com/menu/validator/
│ ├── model/ # Domain models
│ │ ├── MenuDocument.java
│ │ ├── MenuItem.java
│ │ ├── Item.java
│ │ ├── ItemGrouping.java
│ │ ├── Modifier.java
│ │ ├── ModifierGrouping.java
│ │ └── GeneratedMetadata.java
│ ├── enums/ # Enumerations
│ │ ├── ObjectType.java
│ │ └── ItemTypeTag.java
│ ├── util/ # Utilities
│ │ └── S3Helper.java # AWS S3 integration
│ └── examples/ # Usage examples
│ └── S3HelperExample.java
└── test/
└── java/com/menu/validator/
├── validators/
│ └── SpotlightMenuValidatorTest.java
└── util/
└── S3HelperTest.java
-
Java 21: Ensure Java 21 is installed
java -version # Should show Java 21 -
AWS Credentials (for S3 integration): Configure
~/.aws/credentials[default] aws_access_key_id = YOUR_ACCESS_KEY aws_secret_access_key = YOUR_SECRET_KEY
./gradlew build# Run all tests
./gradlew test
# Run specific test
./gradlew test --tests SpotlightMenuValidatorTest
./gradlew test --tests S3HelperTestThe S3Helper class enables fetching JSON files from AWS S3 buckets.
import com.fasterxml.jackson.databind.JsonNode;
import com.menu.validator.util.S3Helper;
S3Helper s3Helper = new S3Helper();
// Fetch JSON from S3
String s3Path = "s3://my-bucket/menus/menu.json";
JsonNode json = s3Helper.fetchJsonFromS3(s3Path);
// Access JSON data
String location = json.get("location").asText();
int categories = json.get("categories").size();import software.amazon.awssdk.regions.Region;
S3Helper s3Helper = new S3Helper();
// Fetch with custom profile and region
JsonNode json = s3Helper.fetchJsonFromS3(
"s3://prod-bucket/menu.json",
"production", // AWS profile name
Region.US_WEST_2 // AWS region
);See S3_HELPER_USAGE.md for comprehensive documentation.
The validator compares menu documents and detects differences:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.menu.validator.model.MenuDocument;
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Load menus
MenuDocument before = mapper.readValue(new File("before.json"), MenuDocument.class);
MenuDocument after = mapper.readValue(new File("after.json"), MenuDocument.class);
// Compare hashes
String hashBefore = before.getGenerated().getMenuPublishing().getMenuHashCode();
String hashAfter = after.getGenerated().getMenuPublishing().getMenuHashCode();
if (!hashBefore.equals(hashAfter)) {
// Perform deep comparison
// See SpotlightMenuValidatorTest for full example
}- Location-specific loyalty menus
- Rich metadata (images, descriptions, pricing)
- Object types:
ITEM,ITEM_GROUPING - Offer types: spotlight-specific promotions
- Digital board/kiosk menus
- Modifier support for customization
- Object types:
ITEM,ITEM_GROUPING,MODIFIER,MODIFIER_GROUPING - Day part and meal configuration
MenuDocument
├── location: String
├── language: String
├── country: String
├── destination: String
├── destinationType: String
├── categories: List<MenuItem>
└── generated: GeneratedMetadata
└── menuPublishing
├── menuHashCode: String
└── rawHashCode: String
MenuItem (abstract)
├── Item
├── ItemGrouping
├── Modifier
└── ModifierGrouping
Set Java 21 for Gradle:
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
./gradlew buildOr use the wrapper with explicit Java home:
env JAVA_HOME="/path/to/java-21" ./gradlew buildDefault region is us-east-1. Override in code:
import software.amazon.awssdk.regions.Region;
s3Helper.fetchJsonFromS3(path, "default", Region.US_WEST_2);See the examples package for complete usage examples:
S3HelperExample.java- S3 integration examples
# Run all tests
./gradlew test
# Run with coverage
./gradlew test jacocoTestReportFor S3 integration tests, ensure valid AWS credentials are configured:
# Set credentials in ~/.aws/credentials
# Then run tests
./gradlew test --tests S3HelperTestIf you see "Unsupported class file major version 69":
# Check Java version
java -version
# Should be Java 21. If not, set JAVA_HOME:
export JAVA_HOME=$(/usr/libexec/java_home -v 21)If you see "AWS credentials file not found":
- Create
~/.aws/credentialsfile - Add your AWS credentials
- Verify file permissions:
chmod 600 ~/.aws/credentials
If Gradle wrapper fails:
# Re-download wrapper
curl -L -o gradle/wrapper/gradle-wrapper.jar \
https://raw.githubusercontent.com/gradle/gradle/v8.14.0/gradle/wrapper/gradle-wrapper.jar
# Make executable
chmod +x gradlew[Specify your license here]
[Add contribution guidelines here]