-
Notifications
You must be signed in to change notification settings - Fork 176
Provide a Java version of the code #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…cement behavior
This commit achieves 100% cross-platform compatibility between the Java
and JavaScript implementations (all 25 test vectors now pass).
Key changes:
1. Add missing character 15 (Street) SVG data and themes
- Character 15 was missing from SvgData.java, causing failures for
test cases that used characters with hash values mapping to 15
- Added all 6 SVG parts (env, clo, head, mouth, eyes, top) for
character 15 from the JavaScript source
2. Fix color replacement algorithm to match JavaScript behavior
- JavaScript uses String.replace() in a loop, which has a quirk:
when you replace A→B, then later B→C, it may re-replace the newly
created B value (cascading replacements)
- Java was using Matcher.appendReplacement() which processes matches
strictly left-to-right without this cascading behavior
- Changed to use replaceFirst() in a loop to exactly match JavaScript
- This "bug-for-bug" compatibility is necessary for identical output
Test results:
- Before: 18/25 tests passing (72%)
- After: 25/25 tests passing (100%)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The tests were expecting valid SVG output for empty/null inputs, but the JavaScript implementation returns an empty string in these cases. Updated assertions to match the actual (and correct) behavior: - Empty string input returns empty string - Null input returns empty string This is verified by test-vectors.json case 6 which confirms JS returns empty string for empty input. All tests now pass (12/12). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This file was a placeholder that is no longer needed. All SVG data is now stored in SvgData.java as Java code, not loaded from JSON. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed from git:// and ssh:// protocols to https:// for better compatibility and security. The git:// protocol is deprecated and blocked by many firewalls. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added build resources configuration to include the LICENSE file in the JAR artifact. This is important because Multiavatar uses a custom license (MULTIAVATAR LICENSE v1.0) with specific restrictions that users need to be aware of when using the library. The LICENSE file is now packaged at META-INF/LICENSE in the JAR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added GenerateExamplesTest that creates 33 example avatar SVG files in target/examples/ for manual inspection: - 20 avatars from various input strings (names, emails, etc.) - 4 avatars without background (sansEnv=true) - 9 avatars with forced versions (3 characters × 3 themes) Run with: mvn test -Dtest=GenerateExamplesTest The generated SVG files can be opened in any web browser to view the avatars and verify the visual output. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Modified the Java implementation to include proper SVG metadata with
Dublin Core properties for attribution. This fulfills the attribution
requirement specified in the MULTIAVATAR LICENSE v1.0.
Changes:
- Multiavatar.java: Added <metadata> element with dc:creator and
dc:source after opening <svg> tag
- CrossPlatformCompatibilityTest: Strip metadata before comparing
with JavaScript output (intentional difference for license compliance)
- MultiavatarTest: Added assertions to verify metadata is present
The metadata format follows SVG best practices:
<metadata>
<dc:creator>Multiavatar</dc:creator>
<dc:source>https://multiavatar.com</dc:source>
</metadata>
This provides proper semantic attribution rather than just a comment,
making it easier for users to comply with license terms while following
SVG standards.
All tests pass (13/13).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Moved the xmlns:dc namespace declaration from the root <svg> element to the <metadata> element itself, keeping the namespace declaration local to where it's used. This is cleaner and doesn't affect the rest of the SVG structure. Generated SVGs now include: <metadata xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:creator>Multiavatar</dc:creator> <dc:source>https://multiavatar.com</dc:source> </metadata> All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Created an enum to represent the six avatar parts (ENV, HEAD, CLO, TOP, EYES, MOUTH) in their rendering order. This provides: - Type safety when iterating over parts - Clear documentation of the rendering order - Better maintainability vs hardcoded string arrays The enum maintains the original string values for compatibility with existing methods like getFinalSvg() and getValue(). All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Refactored all internal methods to use AvatarPart enum instead of string-based part names: - Parts.getValue() now accepts AvatarPart instead of String - getFinalSvg() now accepts AvatarPart instead of String - getColorsForPart() now accepts AvatarPart instead of String - Main loop no longer converts enum to string Strings are now only used at the boundary with SvgData.getSvgPart() which still uses strings for lookups. This eliminates all the string-based switch statements and provides full type safety throughout the avatar generation process. All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Completed the enum refactoring by updating SvgData: - Changed internal storage from Map<String, Map<String, String>> to Map<String, EnumMap<AvatarPart, String>> - Updated all 16 character definitions to use enum constants (ENV, CLO, HEAD, MOUTH, EYES, TOP) instead of strings - Changed getSvgPart() to accept AvatarPart instead of String - Made AvatarPart package-private so SvgData can access it - Updated DebugTest to use the new enum-based API Benefits: - Complete elimination of string-based part names throughout codebase - Type safety at compile time - impossible to use invalid part names - EnumMap provides better performance than HashMap for enum keys - Single source of truth for part names in the AvatarPart enum All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Created AvatarCharacter enum with all 16 character types: ROBO, GIRL, BLONDE, GUY, COUNTRY, GEEKNOT, ASIAN, PUNK, AFROHAIR, NORMIE_FEMALE, OLDER, FIREHAIR, BLOND, ATEAM, RASTA, STREET Changes: - SvgData now uses EnumMap<AvatarCharacter, EnumMap<AvatarPart, String>> instead of Map<String, EnumMap<AvatarPart, String>> - All 16 character definitions use enum constants instead of "00"-"15" - getSvgPart() accepts AvatarCharacter instead of String - Added fromId() and fromIndex() helper methods for conversion - Updated DebugTest to use the new enum-based API Benefits: - No more magic strings like "00", "05", "15" - Type-safe character selection - Self-documenting code with meaningful names (ROBO vs "00") - EnumMap provides better performance than HashMap - Impossible to reference non-existent characters at compile time All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Updated ThemeData to use the AvatarCharacter enum: - Changed internal storage from Map<String, CharacterThemes> to EnumMap<AvatarCharacter, CharacterThemes> - Updated all 16 character theme definitions to use enum constants instead of "00"-"15" strings - Changed getCharacterThemes() to accept AvatarCharacter instead of String - Updated test files to use the enum-based API Benefits: - Complete elimination of character ID strings throughout the codebase - Type safety when accessing theme data - EnumMap provides better performance than HashMap - Self-documenting code (GEEKNOT vs "05") - Compile-time verification of valid character references The only remaining string usage is the partId variable in getFinalSvg(), which is converted to AvatarCharacter enum immediately. This string comes from the hash-based part selection algorithm and is the boundary between the hash calculation and the type-safe enum system. All tests pass (13/13). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Compensate fix of absurd expansion strategy with fixed theme data values.
Replace string-based encoding of part ID and theme (e.g., "05A") with explicit PartWithTheme value class that holds AvatarCharacter and Theme. Changes: - Add Theme enum (A, B, C) and PartWithTheme value class - Update Parts helper class to store PartWithTheme instead of strings - Update Version class to use AvatarCharacter instead of string part ID - Remove getPartWithTheme() method and inline logic into PartWithTheme - Update getFinalSvg() to accept AvatarCharacter directly - Remove deprecated string-based Version constructor - Update all tests and documentation to use new API Benefits: - Type safety: Using enums prevents invalid values - Clearer code: Explicit structure instead of string encoding/decoding - No more lookups: Eliminated AvatarCharacter.fromId() calls - Better semantics: Code directly expresses domain concepts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Refactor CharacterThemes to use Multiavatar.Theme enum internally instead of having redundant A, B, C fields and char-based lookup. Changes: - CharacterThemes now uses EnumMap<Multiavatar.Theme, Theme> internally - Update getTheme() to accept Multiavatar.Theme enum instead of char - Update Version class to use Theme enum instead of char - Update getFinalSvg() to accept Theme enum instead of char - Update all test files to use Theme enum - Update documentation to use Theme enum Benefits: - Eliminates redundancy between separate A/B/C fields and Theme enum - Type safety: Using enum prevents invalid theme values - Cleaner API: No more char-based lookups - Single source of truth for theme variants 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The Version class was only used to pass parameters to generate(). Replace it with direct parameters for a cleaner API. Changes: - Add generate(String, boolean, AvatarCharacter, Theme) overload - Remove Version class entirely - Update all test files to use direct parameters - Update documentation to use direct parameters Benefits: - Simpler API: No need to create wrapper objects - Fewer classes: Removed unnecessary Version class - Clearer intent: Parameters directly show what's being forced - Less boilerplate: Direct parameter passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The previous API mixed two concerns: generating an avatar from a string ID versus using a predefined character/theme. Split into two separate methods with shared rendering logic. Changes: - Add generate(CharacterType, CharacterTheme) for predefined avatars - Add generate(CharacterType, CharacterTheme, boolean) with sansEnv option - Keep generate(String) and generate(String, boolean) for ID-based generation - Extract shared renderAvatar(Avatar, boolean) method to avoid duplication - Add Avatar.fromCharacterTheme() factory method - Remove confusing generate(String, boolean, CharacterType, CharacterTheme) - Update all tests to use appropriate API - Update documentation Benefits: - Clear separation of concerns: ID-based vs predefined avatars - No more confusing mixed parameters - Cleaner API: each method has a single, clear purpose - No code duplication: shared rendering logic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The render method operates on Avatar data, so it should be an instance method. Also rename the confusing 'string' parameter to 'id' to clarify that it's an identifier for the avatar. Changes: - Move renderAvatar() from static method to Avatar.render() instance method - Update generate() methods to call avatar.render() - Rename 'string' parameter to 'id' throughout - Update javadoc to clarify that 'id' can be username, email, etc. Benefits: - Better encapsulation: Avatar knows how to render itself - Clearer naming: 'id' is more descriptive than 'string' - Better OOP design: behavior is with the data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Introduce Avatar.fromRandom(Random) and Multiavatar.generate(Random) methods to support generating avatars with random parts using a provided Random instance. This enables reproducible random avatar generation when needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add JavaDoc {@link} tags for all class references in documentation
- Add complete JavaDoc for Avatar.pure() and Avatar.fromId() methods
- Update Multiavatar class documentation to include all generation modes
- Fix outdated comment references (PartWithTheme → Coordinate)
- Update README-JAVA.md with current API (remove Version class references)
- Add documentation for random avatar generation methods
- Fix character 15 name in README: "Meta" → "Street"
- Update code examples with proper imports and current API usage
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Introduce generate(long seed) and generate(long seed, boolean sansEnv) methods to support reproducible random avatar generation. The seed is used to create a new Random instance, ensuring the same seed always produces the same avatar. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Update test vector generation to include all 48 pure avatar combinations (16 characters × 3 themes) with and without backgrounds, bringing total test vectors from 25 to 132. This ensures comprehensive cross-platform compatibility testing between JavaScript and Java implementations. Changes: - Rename generate-test-vectors.js to .cjs for CommonJS compatibility - Add automatic generation of all pure avatar test cases - Fix API call to properly handle null/undefined for hash-based generation - Update test-vectors.json with 96 additional pure avatar test cases - Add TEST-VECTORS.md documentation explaining how to generate and update test vectors All 132 test vectors pass in CrossPlatformCompatibilityTest. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Document each avatar part constant with its purpose and layer description: - ENV: Environment/circular background layer - HEAD: Face/head shape layer - CLO: Clothing/body layer - TOP: Hair/headwear layer - EYES: Eyes layer - MOUTH: Mouth/expression layer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Hi, thanks for the PR. The Java version would be better as a separate repository (e.g. multiavatar/multiavatar-java) rather than merged into the main JS repo. If we go that route, are you willing to fully prepare it (including tests, documentation, and packaging) and take long-term responsibility for maintaining the Java implementation? I'd keep my role limited to the reference JS version and overall direction. |
|
Yes, I can do that. Of cause, I'll need your help to get access to the corresponding namespace in Maven Central - requires some DNS proof of domain ownership. |
To use the library in Java server applications, it would be wonderful to have a Java version of the code. It would be even more useful, if the library could be imported as dependency from Maven Central.
Besides translation, I added an attribution to the generated SVG images according to the LICENSE requirements.
I intentionally added the Java version to the same repo to easy synching changes, but I also could move the Java version to a separate library under the "home" of Multiavatar.
If you whish, I could help preparing the library for deploying to Maven central. I used the Maven coordinates