Skip to content

MBA-72: Migrate from Joda Time to java.time API#570

Open
devin-ai-integration[bot] wants to merge 7 commits intomasterfrom
devin/1776956749-joda-time-to-java-time-migration
Open

MBA-72: Migrate from Joda Time to java.time API#570
devin-ai-integration[bot] wants to merge 7 commits intomasterfrom
devin/1776956749-joda-time-to-java-time-migration

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot commented Apr 23, 2026

Summary

Replaces all Joda Time (org.joda.time.DateTime) usage with java.time.Instant across the entire codebase and removes the joda-time:2.10.13 dependency.

Changes span 17 files across 4 layers:

  • Domain entities (Article, Comment): DateTime fields → Instant
  • DTOs (ArticleData, CommentData): same field type change
  • Infrastructure (DateTimeHandler): MyBatis TypeHandler rewritten for InstantTimestamp conversion using Timestamp.from() / toInstant()
  • Serialization: Jackson custom serializer and GraphQL datafetchers now use DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(ZoneOffset.UTC) instead of Joda's ISODateTimeFormat
  • Pagination (DateTimeCursor): uses toEpochMilli() / Instant.ofEpochMilli() instead of Joda equivalents
  • Tests: all 4 test files updated to use Instant.now() and java.time formatters

Review & Testing Checklist for Human

  • Date format output parity: Verify that the java.time formatter yyyy-MM-dd'T'HH:mm:ss.SSS'Z' produces output identical to Joda's ISODateTimeFormat.dateTime().withZoneUTC(), especially at boundary values (e.g. zero millis, midnight). Both should produce 2024-01-01T00:00:00.000Z but edge cases around sub-millisecond precision may differ.
  • MyBatis DateTimeHandler round-trip: Confirm that Timestamp.from(instant) and timestamp.toInstant() preserve the same precision as the prior new Timestamp(dateTime.getMillis()) / new DateTime(timestamp.getTime()) path, particularly with your production database (the test suite uses SQLite).
  • No residual Joda transitive dependency: Confirm no other library in the dependency tree still pulls in or requires Joda Time at runtime.
  • GraphQL datafetchers create DateTimeFormatter inline on every call rather than using a static final constant (unlike JacksonCustomizations which does extract it). Not a correctness issue, but worth deciding if you want consistency.

Recommended test plan: Start the application locally, create an article via POST /articles, and verify the createdAt/updatedAt fields in the JSON response match the expected ISO-8601 format. Also verify cursor-based pagination (/articles?cursor=...) still works correctly.

Notes

  • Instant.now().minusSeconds(3600) replaces new DateTime().minusHours(1) in tests — semantically equivalent.
  • All existing tests pass. Spotless formatting applied.

Link to Devin session: https://app.devin.ai/sessions/c260e1d5a9ba4fee99beb1cd4cbb818a
Requested by: @shayanshafii


Open in Devin Review

gardnerjohnson-creator and others added 7 commits August 26, 2025 01:47
- Added a simple note confirming RealWorld API spec compliance
- This is a test change to verify PR workflow functionality

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
…st-dummy-change

Test: Add testing verification note to README
- Modern React 18 frontend with TypeScript and Tailwind CSS
- Complete RealWorld specification implementation
- User authentication with JWT token management
- Article management (create, view, edit, delete)
- Article feed with pagination
- User profiles and following functionality
- Comments system for articles
- Social features (favorites, following)
- Tag-based article categorization
- Responsive design with modern UI
- Full API integration with Spring Boot backend
- Development server on localhost:3000
- Production build support

Features implemented:
- User registration and login
- Article creation and editing with markdown support
- Global article feed
- User profiles and social following
- Comment system
- Article favoriting
- Tag filtering
- JWT authentication integration
- Error handling and validation
- Modern responsive UI design

The frontend successfully demonstrates all backend API functionality
through a visual web interface, replacing raw JSON responses with
a complete social blogging platform user experience.

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
- Remove node_modules from git tracking and add to .gitignore
- Configure environment variables for API base URL using VITE_API_BASE_URL
- Add TypeScript definitions for Vite environment variables
- Remove unused 'User' import to fix TypeScript error

Addresses the 5 critical issues identified in PR review:
1. ✅ Remove node_modules from git (added to .gitignore)
2. 🔄 Test complete user journey (next step)
3. ✅ Configure environment variables (VITE_API_BASE_URL)
4. 🔄 Verify CORS configuration (next step)
5. 🔄 Test authentication flow thoroughly (next step)

Co-Authored-By: Gardner Johnson <gardnerjohnson@gmail.com>
…d-react-frontend

Add React Frontend Application for RealWorld API
- Replace all org.joda.time.DateTime usage with java.time.Instant
- Update MyBatis DateTimeHandler for java.time compatibility
- Update Jackson serialization to use DateTimeFormatter
- Update GraphQL datafetchers date formatting
- Update cursor-based pagination (DateTimeCursor)
- Update all service classes and DTOs
- Update all test files
- Remove joda-time:2.10.13 dependency from build.gradle
- Apply spotless formatting fixes

All tests pass with identical date/time functionality.

Co-Authored-By: shayan <shayan@cognition.ai>
Copy link
Copy Markdown
Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +63 to +66
const updateUser = async (userData: Partial<UserWithToken>) => {
const updatedUser = await authApi.updateUser(userData);
setUser(updatedUser);
};
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 updateUser does not persist token to localStorage, breaking consistency with login/register

In useAuth.ts, both login (line 48) and register (line 54) save the returned token to localStorage.setItem('token', userData.token) before calling setUser. However, updateUser at line 63-66 only calls setUser(updatedUser) without saving the token. This means the token in localStorage and the token in React state can diverge. While the current backend (CurrentUserApi.java:48) echoes back the same token, if the response token ever differs (e.g., token rotation, claims update), all subsequent API calls would use the stale localStorage token via the axios interceptor (api.ts:24), causing authentication failures.

Suggested change
const updateUser = async (userData: Partial<UserWithToken>) => {
const updatedUser = await authApi.updateUser(userData);
setUser(updatedUser);
};
const updateUser = async (userData: Partial<UserWithToken>) => {
const updatedUser = await authApi.updateUser(userData);
localStorage.setItem('token', updatedUser.token);
setUser(updatedUser);
};
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant