CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-dropwizard--dropwizard-jersey

Dropwizard Jersey Support - Jersey integration module for the Dropwizard Java framework

Pending
Overview
Eval results
Files

jsr310-parameters.mddocs/

JSR310 Date/Time Parameters

Parameter converters for Java 8 date/time API types providing type-safe parsing of date and time values from HTTP requests. Supports all major JSR310 temporal types with automatic validation and error handling.

Capabilities

Instant Parameters

Parameter converters for Instant values representing points in time.

/**
 * Parameter wrapper for Instant values
 * Parses ISO-8601 instant strings (e.g., "2023-12-25T10:30:00Z")
 */
public class InstantParam extends AbstractParam<Instant> {
    
    /** Creates InstantParam from ISO-8601 string input */
    public InstantParam(String input);
    
    /** Creates InstantParam with custom parameter name for error messages */
    public InstantParam(String input, String parameterName);
}

/**
 * Parameter wrapper for Instant values from seconds since epoch
 * Parses numeric strings as seconds since Unix epoch
 */
public class InstantSecondParam extends AbstractParam<Instant> {
    
    /** Creates InstantSecondParam from seconds string input */
    public InstantSecondParam(String input);
    
    /** Creates InstantSecondParam with custom parameter name */
    public InstantSecondParam(String input, String parameterName);
}

Usage Examples:

import io.dropwizard.jersey.jsr310.*;
import jakarta.ws.rs.*;
import java.time.Instant;

@Path("/events")
public class EventResource {
    
    @GET
    public List<Event> getEvents(@QueryParam("since") InstantParam since,
                               @QueryParam("until") InstantParam until) {
        Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(7));
        Instant untilTime = until != null ? until.get() : Instant.now();
        
        return eventService.getEventsBetween(sinceTime, untilTime);
    }
    
    @GET
    @Path("/unix")
    public List<Event> getEventsUnix(@QueryParam("since") InstantSecondParam since) {
        // Handles Unix timestamps like "1703505000"
        Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(1));
        return eventService.getEventsSince(sinceTime);
    }
}

// Example URLs:
// GET /events?since=2023-12-25T10:30:00Z&until=2023-12-26T10:30:00Z
// GET /events/unix?since=1703505000

Local Date/Time Parameters

Parameter converters for local date and time values without timezone information.

/**
 * Parameter wrapper for LocalDate values
 * Parses ISO-8601 date strings (e.g., "2023-12-25")
 */
public class LocalDateParam extends AbstractParam<LocalDate> {
    
    /** Creates LocalDateParam from ISO-8601 date string */
    public LocalDateParam(String input);
    
    /** Creates LocalDateParam with custom parameter name */
    public LocalDateParam(String input, String parameterName);
}

/**
 * Parameter wrapper for LocalDateTime values
 * Parses ISO-8601 date-time strings (e.g., "2023-12-25T10:30:00")
 */
public class LocalDateTimeParam extends AbstractParam<LocalDateTime> {
    
    /** Creates LocalDateTimeParam from ISO-8601 date-time string */
    public LocalDateTimeParam(String input);
    
    /** Creates LocalDateTimeParam with custom parameter name */
    public LocalDateTimeParam(String input, String parameterName);
}

/**
 * Parameter wrapper for LocalTime values
 * Parses ISO-8601 time strings (e.g., "10:30:00")
 */
public class LocalTimeParam extends AbstractParam<LocalTime> {
    
    /** Creates LocalTimeParam from ISO-8601 time string */
    public LocalTimeParam(String input);
    
    /** Creates LocalTimeParam with custom parameter name */
    public LocalTimeParam(String input, String parameterName);
}

Usage Examples:

import java.time.*;
import jakarta.ws.rs.*;

@Path("/schedule")
public class ScheduleResource {
    
    @GET
    @Path("/daily")
    public List<Appointment> getDailySchedule(@QueryParam("date") LocalDateParam date) {
        LocalDate scheduleDate = date != null ? date.get() : LocalDate.now();
        return scheduleService.getAppointmentsForDate(scheduleDate);
    }
    
    @GET
    @Path("/appointments")
    public List<Appointment> getAppointments(@QueryParam("from") LocalDateTimeParam from,
                                           @QueryParam("to") LocalDateTimeParam to) {
        LocalDateTime fromTime = from != null ? from.get() : LocalDateTime.now();
        LocalDateTime toTime = to != null ? to.get() : fromTime.plusDays(1);
        
        return scheduleService.getAppointmentsBetween(fromTime, toTime);
    }
    
    @GET
    @Path("/available")
    public List<TimeSlot> getAvailableSlots(@QueryParam("date") LocalDateParam date,
                                          @QueryParam("after") LocalTimeParam afterTime) {
        LocalDate checkDate = date != null ? date.get() : LocalDate.now();
        LocalTime startTime = afterTime != null ? afterTime.get() : LocalTime.of(9, 0);
        
        return scheduleService.getAvailableSlots(checkDate, startTime);
    }
}

// Example URLs:
// GET /schedule/daily?date=2023-12-25
// GET /schedule/appointments?from=2023-12-25T09:00:00&to=2023-12-25T17:00:00
// GET /schedule/available?date=2023-12-25&after=10:30:00

Offset and Zoned Date/Time Parameters

Parameter converters for date/time values with timezone information.

/**
 * Parameter wrapper for OffsetDateTime values
 * Parses ISO-8601 offset date-time strings (e.g., "2023-12-25T10:30:00+01:00")
 */
public class OffsetDateTimeParam extends AbstractParam<OffsetDateTime> {
    
    /** Creates OffsetDateTimeParam from ISO-8601 offset date-time string */
    public OffsetDateTimeParam(String input);
    
    /** Creates OffsetDateTimeParam with custom parameter name */
    public OffsetDateTimeParam(String input, String parameterName);
}

/**
 * Parameter wrapper for ZonedDateTime values
 * Parses ISO-8601 zoned date-time strings (e.g., "2023-12-25T10:30:00[Europe/London]")
 */
public class ZonedDateTimeParam extends AbstractParam<ZonedDateTime> {
    
    /** Creates ZonedDateTimeParam from ISO-8601 zoned date-time string */
    public ZonedDateTimeParam(String input);
    
    /** Creates ZonedDateTimeParam with custom parameter name */
    public ZonedDateTimeParam(String input, String parameterName);
}

/**
 * Parameter wrapper for ZoneId values
 * Parses zone ID strings (e.g., "Europe/London", "UTC", "+01:00")
 */
public class ZoneIdParam extends AbstractParam<ZoneId> {
    
    /** Creates ZoneIdParam from zone ID string */
    public ZoneIdParam(String input);
    
    /** Creates ZoneIdParam with custom parameter name */
    public ZoneIdParam(String input, String parameterName);
}

Usage Examples:

import java.time.*;
import jakarta.ws.rs.*;

@Path("/global")
public class GlobalTimeResource {
    
    @GET
    @Path("/meetings")
    public List<Meeting> getMeetings(@QueryParam("start") OffsetDateTimeParam start,
                                   @QueryParam("timezone") ZoneIdParam timezone) {
        
        OffsetDateTime startTime = start != null ? start.get() : OffsetDateTime.now();
        ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();
        
        return meetingService.getMeetingsInTimezone(startTime, zone);
    }
    
    @GET
    @Path("/schedule/{zone}")
    public WorkSchedule getScheduleForZone(@PathParam("zone") ZoneIdParam zoneParam,
                                         @QueryParam("date") LocalDateParam date) {
        
        ZoneId zone = zoneParam.get();
        LocalDate scheduleDate = date != null ? date.get() : LocalDate.now(zone);
        
        return scheduleService.getScheduleForZone(zone, scheduleDate);
    }
    
    @POST
    @Path("/events")
    public Response createEvent(@FormParam("startTime") ZonedDateTimeParam startTime,
                              @FormParam("endTime") ZonedDateTimeParam endTime,
                              @Valid CreateEventRequest request) {
        
        Event event = eventService.createEvent(
            request, 
            startTime.get(), 
            endTime.get()
        );
        
        return Response.status(201).entity(event).build();
    }
}

// Example URLs:
// GET /global/meetings?start=2023-12-25T10:30:00+01:00&timezone=Europe/London
// GET /global/schedule/America/New_York?date=2023-12-25

Year and Month Parameters

Parameter converters for year and year-month values for date range operations.

/**
 * Parameter wrapper for Year values
 * Parses year strings (e.g., "2023")
 */
public class YearParam extends AbstractParam<Year> {
    
    /** Creates YearParam from year string */
    public YearParam(String input);
    
    /** Creates YearParam with custom parameter name */
    public YearParam(String input, String parameterName);
}

/**
 * Parameter wrapper for YearMonth values
 * Parses year-month strings (e.g., "2023-12")
 */
public class YearMonthParam extends AbstractParam<YearMonth> {
    
    /** Creates YearMonthParam from year-month string */
    public YearMonthParam(String input);
    
    /** Creates YearMonthParam with custom parameter name */
    public YearMonthParam(String input, String parameterName);
}

Usage Examples:

import java.time.*;
import jakarta.ws.rs.*;

@Path("/reports")
public class ReportsResource {
    
    @GET
    @Path("/monthly")
    public MonthlyReport getMonthlyReport(@QueryParam("month") YearMonthParam month) {
        YearMonth reportMonth = month != null ? month.get() : YearMonth.now();
        return reportService.getMonthlyReport(reportMonth);
    }
    
    @GET
    @Path("/yearly")
    public YearlyReport getYearlyReport(@QueryParam("year") YearParam year) {
        Year reportYear = year != null ? year.get() : Year.now();
        return reportService.getYearlyReport(reportYear);
    }
    
    @GET
    @Path("/quarterly")
    public List<QuarterlyReport> getQuarterlyReports(@QueryParam("year") YearParam year) {
        Year reportYear = year != null ? year.get() : Year.now();
        
        return List.of(
            reportService.getQuarterlyReport(reportYear, 1),
            reportService.getQuarterlyReport(reportYear, 2),
            reportService.getQuarterlyReport(reportYear, 3),
            reportService.getQuarterlyReport(reportYear, 4)
        );
    }
    
    @GET
    @Path("/range")
    public Report getReportForRange(@QueryParam("from") YearMonthParam from,
                                  @QueryParam("to") YearMonthParam to) {
        
        YearMonth fromMonth = from != null ? from.get() : YearMonth.now().minusMonths(12);
        YearMonth toMonth = to != null ? to.get() : YearMonth.now();
        
        return reportService.getReportForRange(fromMonth, toMonth);
    }
}

// Example URLs:
// GET /reports/monthly?month=2023-12
// GET /reports/yearly?year=2023
// GET /reports/range?from=2023-01&to=2023-12

Date/Time Patterns and Formats

Supported Input Formats

public class DateTimeFormats {
    
    // InstantParam supports:
    // "2023-12-25T10:30:00Z"
    // "2023-12-25T10:30:00.123Z"  
    // "2023-12-25T10:30:00+01:00"
    
    // InstantSecondParam supports:
    // "1703505000" (Unix timestamp in seconds)
    
    // LocalDateParam supports:
    // "2023-12-25"
    
    // LocalDateTimeParam supports:
    // "2023-12-25T10:30:00"
    // "2023-12-25T10:30:00.123"
    
    // LocalTimeParam supports:
    // "10:30:00"
    // "10:30:00.123"
    // "10:30"
    
    // OffsetDateTimeParam supports:
    // "2023-12-25T10:30:00+01:00"
    // "2023-12-25T10:30:00-05:00"
    // "2023-12-25T10:30:00Z"
    
    // ZonedDateTimeParam supports:
    // "2023-12-25T10:30:00[Europe/London]"
    // "2023-12-25T10:30:00+01:00[Europe/London]"
    
    // ZoneIdParam supports:
    // "UTC"
    // "Europe/London"
    // "America/New_York"
    // "+01:00"
    // "-05:00"
    
    // YearParam supports:
    // "2023"
    
    // YearMonthParam supports:
    // "2023-12"
}

Error Handling

All JSR310 parameter types provide consistent error handling:

@Path("/dates")
public class DateErrorHandlingResource {
    
    @GET
    public Response getDataForDate(@QueryParam("date") LocalDateParam date) {
        try {
            LocalDate actualDate = date.get(); // May throw WebApplicationException
            Data data = dataService.getDataForDate(actualDate);
            return Response.ok(data).build();
            
        } catch (WebApplicationException e) {
            // Parameter parsing failed - returns 400 Bad Request
            // Error message will be: "date is not a valid date format"
            throw e;
        }
    }
}

// Invalid input examples that result in 400 errors:
// GET /dates?date=invalid-date
// GET /dates?date=2023-13-45  (invalid month/day)
// GET /dates?date=25-12-2023  (wrong format)

Advanced Usage Patterns

Date Range Queries

@Path("/analytics")
public class AnalyticsResource {
    
    @GET
    @Path("/sales")
    public SalesReport getSalesReport(@QueryParam("from") LocalDateParam from,
                                    @QueryParam("to") LocalDateParam to,
                                    @QueryParam("timezone") ZoneIdParam timezone) {
        
        LocalDate fromDate = from != null ? from.get() : LocalDate.now().minusDays(30);
        LocalDate toDate = to != null ? to.get() : LocalDate.now();
        ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();
        
        // Convert to start/end of day in specified timezone
        ZonedDateTime startTime = fromDate.atStartOfDay(zone);
        ZonedDateTime endTime = toDate.plusDays(1).atStartOfDay(zone);
        
        return analyticsService.getSalesReport(startTime, endTime);
    }
    
    @GET
    @Path("/activity")
    public ActivityReport getActivityReport(@QueryParam("month") YearMonthParam month,
                                          @QueryParam("timezone") ZoneIdParam timezone) {
        
        YearMonth reportMonth = month != null ? month.get() : YearMonth.now();
        ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();
        
        // Get first and last day of month in timezone
        LocalDate firstDay = reportMonth.atDay(1);
        LocalDate lastDay = reportMonth.atEndOfMonth();
        
        ZonedDateTime start = firstDay.atStartOfDay(zone);
        ZonedDateTime end = lastDay.plusDays(1).atStartOfDay(zone);
        
        return analyticsService.getActivityReport(start, end);
    }
}

Time-based Resource Filtering

@Path("/logs")
public class LogResource {
    
    @GET
    public List<LogEntry> getLogs(@QueryParam("since") InstantParam since,
                                @QueryParam("level") String level,
                                @QueryParam("limit") Integer limit) {
        
        Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofHours(1));
        int maxResults = limit != null ? limit : 100;
        
        return logService.getLogs(sinceTime, level, maxResults);
    }
    
    @GET
    @Path("/between")
    public List<LogEntry> getLogsBetween(@QueryParam("start") InstantParam start,
                                       @QueryParam("end") InstantParam end) {
        
        if (start == null || end == null) {
            throw new WebApplicationException("Both start and end times are required", 400);
        }
        
        Instant startTime = start.get();
        Instant endTime = end.get();
        
        if (startTime.isAfter(endTime)) {
            throw new WebApplicationException("Start time must be before end time", 400);
        }
        
        return logService.getLogsBetween(startTime, endTime);
    }
}

Timezone-aware Operations

@Path("/meetings")
public class MeetingResource {
    
    @POST
    public Response scheduleMeeting(@FormParam("startTime") ZonedDateTimeParam startTime,
                                  @FormParam("duration") Integer durationMinutes,
                                  @FormParam("attendeeTimezone") ZoneIdParam attendeeZone,
                                  @Valid ScheduleMeetingRequest request) {
        
        ZonedDateTime meetingStart = startTime.get();
        Duration duration = Duration.ofMinutes(durationMinutes != null ? durationMinutes : 60);
        ZoneId attendeeTimezone = attendeeZone != null ? attendeeZone.get() : ZoneId.systemDefault();
        
        // Convert meeting time to attendee's timezone for confirmation
        ZonedDateTime localStartTime = meetingStart.withZoneSameInstant(attendeeTimezone);
        
        Meeting meeting = meetingService.scheduleMeeting(
            request, 
            meetingStart, 
            duration,
            attendeeTimezone
        );
        
        return Response.status(201)
            .entity(meeting)
            .header("X-Local-Start-Time", localStartTime.toString())
            .build();
    }
    
    @GET
    @Path("/availability")
    public AvailabilityResponse getAvailability(@QueryParam("date") LocalDateParam date,
                                              @QueryParam("timezone") ZoneIdParam timezone,
                                              @QueryParam("duration") Integer durationMinutes) {
        
        LocalDate checkDate = date != null ? date.get() : LocalDate.now();
        ZoneId zone = timezone != null ? timezone.get() : ZoneId.systemDefault();
        Duration meetingDuration = Duration.ofMinutes(durationMinutes != null ? durationMinutes : 30);
        
        return meetingService.getAvailability(checkDate, zone, meetingDuration);
    }
}

Best Practices

Parameter Validation

@Path("/validation")
public class DateValidationResource {
    
    @GET
    @Path("/future-events")
    public List<Event> getFutureEvents(@QueryParam("from") LocalDateParam from) {
        
        LocalDate fromDate = from != null ? from.get() : LocalDate.now();
        
        // Validate that date is not too far in the past
        if (fromDate.isBefore(LocalDate.now().minusYears(1))) {
            throw new WebApplicationException("Date cannot be more than 1 year in the past", 400);
        }
        
        // Validate that date is not too far in the future
        if (fromDate.isAfter(LocalDate.now().plusYears(5))) {
            throw new WebApplicationException("Date cannot be more than 5 years in the future", 400);
        }
        
        return eventService.getFutureEventsFrom(fromDate);
    }
    
    @GET
    @Path("/business-hours")
    public List<Appointment> getBusinessHourAppointments(@QueryParam("date") LocalDateParam date,
                                                       @QueryParam("startTime") LocalTimeParam startTime) {
        
        LocalDate appointmentDate = date != null ? date.get() : LocalDate.now();
        LocalTime start = startTime != null ? startTime.get() : LocalTime.of(9, 0);
        
        // Validate business hours
        if (start.isBefore(LocalTime.of(8, 0)) || start.isAfter(LocalTime.of(18, 0))) {
            throw new WebApplicationException("Start time must be between 08:00 and 18:00", 400);
        }
        
        return appointmentService.getAppointments(appointmentDate, start);
    }
}

Default Values and Null Handling

@Path("/defaults")
public class DefaultDateResource {
    
    @GET
    @Path("/recent")
    public List<Item> getRecentItems(@QueryParam("since") InstantParam since) {
        // Provide sensible default if parameter not provided
        Instant sinceTime = since != null ? since.get() : Instant.now().minus(Duration.ofDays(7));
        return itemService.getItemsSince(sinceTime);
    }
    
    @GET
    @Path("/monthly/{year}")
    public MonthlyData getMonthlyData(@PathParam("year") YearParam year,
                                    @QueryParam("month") Integer month) {
        
        Year dataYear = year.get(); // Required path parameter
        
        // Handle optional month parameter
        YearMonth yearMonth;
        if (month != null && month >= 1 && month <= 12) {
            yearMonth = YearMonth.of(dataYear.getValue(), month);
        } else {
            yearMonth = YearMonth.now();
        }
        
        return dataService.getMonthlyData(yearMonth);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-dropwizard--dropwizard-jersey

docs

error-handling.md

framework-configuration.md

http-caching.md

index.md

jsr310-parameters.md

optional-handling.md

parameter-handling.md

session-management.md

validation.md

tile.json