Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,8 @@ runs:
version=$(sed -n 's/version=\(.*\)/\1/p' gradle.properties)
echo "Version is $version"
echo "version=$version" >> $GITHUB_OUTPUT
- name: SanityCheck
Copy link
Author

Choose a reason for hiding this comment

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

I’m not sure if this is the right place to check. Having this last in place should allow most of the other steps to work, but it still ends up failing with a corrupt version.

id: build
if: ${{ inputs.publish == 'false' }}
shell: bash
run: ./gradlew rewriteDryRun -Dorg.gradle.jvmargs=-Xmx8G
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
id 'com.gradleup.shadow' version "9.2.2" apply false
id 'me.champeau.jmh' version '0.7.2' apply false
id 'io.spring.nullability' version '0.0.8' apply false
id 'org.openrewrite.rewrite' version '7.20.0' apply false
}

ext {
Expand All @@ -16,6 +17,8 @@ ext {

description = "Spring Framework"

apply from: "$rootDir/gradle/rewrite.gradle"

configure(allprojects) { project ->
apply plugin: "org.springframework.build.localdev"
group = "org.springframework"
Expand Down
12 changes: 12 additions & 0 deletions gradle/rewrite.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apply plugin: 'org.openrewrite.rewrite'

rewrite {
activeRecipe('org.springframework.openrewrite.SanityCheck')
setExportDatatables(true)
setFailOnDryRunResults(true)
}

dependencies {
rewrite(platform('org.openrewrite.recipe:rewrite-recipe-bom:3.18.0'))
rewrite('org.openrewrite.recipe:rewrite-rewrite:0.15.0')
}
19 changes: 19 additions & 0 deletions rewrite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
type: specs.openrewrite.org/v1beta/recipe
name: org.springframework.openrewrite.SanityCheck
displayName: Apply all Java & Gradle best practices
description: Comprehensive code quality recipe combining modernization, security, and best practices.
tags:
- java
- gradle
- static-analysis
- cleanup
recipeList:
- org.openrewrite.gradle.EnableGradleBuildCache
- org.openrewrite.gradle.EnableGradleParallelExecution
- org.openrewrite.gradle.GradleBestPractices
- tech.picnic.errorprone.refasterrules.TimeRulesRecipes
# TBD
# - org.openrewrite.java.migrate.Java8toJava11 # https://github.com/google/error-prone/pull/5328
# - org.openrewrite.java.migrate.UpgradeToJava17 # https://github.com/checkstyle/checkstyle/pull/17730
Copy link
Author

Choose a reason for hiding this comment

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

Since Checkstyle is already used within Spring, it’s effectively part of the project transitively.

Integrating these rules directly could improve a lot of code and allow best practices to be applied effortlessly and consistently.

---
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ private static ZonedDateTime calendarToZonedDateTime(Calendar source) {
return gc.toZonedDateTime();
}
else {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(source.getTimeInMillis()),
source.getTimeZone().toZoneId());
return Instant.ofEpochMilli(source.getTimeInMillis()).atZone(source.getTimeZone().toZoneId());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public String getExpression() {
public @Nullable Instant nextExecution(TriggerContext triggerContext) {
Instant timestamp = determineLatestTimestamp(triggerContext);
ZoneId zone = (this.zoneId != null ? this.zoneId : triggerContext.getClock().getZone());
ZonedDateTime zonedTimestamp = ZonedDateTime.ofInstant(timestamp, zone);
ZonedDateTime zonedTimestamp = timestamp.atZone(zone);
ZonedDateTime nextTimestamp = this.expression.next(zonedTimestamp);
return (nextTimestamp != null ? nextTimestamp.toInstant() : null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -53,28 +52,28 @@ void scheduleWithInstantAndNoScheduledExecutorProvidesDedicatedException() {
void scheduleAtFixedRateWithStartTimeAndDurationAndNoScheduledExecutorProvidesDedicatedException() {
DefaultManagedTaskScheduler scheduler = new DefaultManagedTaskScheduler();
assertNoExecutorException(() -> scheduler.scheduleAtFixedRate(
NO_OP, Instant.now(), Duration.of(1, ChronoUnit.MINUTES)));
NO_OP, Instant.now(), Duration.ofMinutes(1)));
}

@Test
void scheduleAtFixedRateWithDurationAndNoScheduledExecutorProvidesDedicatedException() {
DefaultManagedTaskScheduler scheduler = new DefaultManagedTaskScheduler();
assertNoExecutorException(() -> scheduler.scheduleAtFixedRate(
NO_OP, Duration.of(1, ChronoUnit.MINUTES)));
NO_OP, Duration.ofMinutes(1)));
}

@Test
void scheduleWithFixedDelayWithStartTimeAndDurationAndNoScheduledExecutorProvidesDedicatedException() {
DefaultManagedTaskScheduler scheduler = new DefaultManagedTaskScheduler();
assertNoExecutorException(() -> scheduler.scheduleWithFixedDelay(
NO_OP, Instant.now(), Duration.of(1, ChronoUnit.MINUTES)));
NO_OP, Instant.now(), Duration.ofMinutes(1)));
}

@Test
void scheduleWithFixedDelayWithDurationAndNoScheduledExecutorProvidesDedicatedException() {
DefaultManagedTaskScheduler scheduler = new DefaultManagedTaskScheduler();
assertNoExecutorException(() -> scheduler.scheduleWithFixedDelay(
NO_OP, Duration.of(1, ChronoUnit.MINUTES)));
NO_OP, Duration.ofMinutes(1)));
}

private void assertNoExecutorException(ThrowingCallable callable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
Expand All @@ -42,7 +43,7 @@
*/
public class HttpHeadersAssert extends AbstractObjectAssert<HttpHeadersAssert, HttpHeaders> {

private static final ZoneId GMT = ZoneId.of("GMT");
private static final ZoneId GMT = ZoneOffset.UTC;


private final AbstractCollectionAssert<?, Collection<? extends String>, String, ObjectAssert<String>> namesAssert;
Expand Down Expand Up @@ -173,7 +174,7 @@ public HttpHeadersAssert hasValue(String name, Instant value) {
containsHeader(name);
Assertions.assertThat(this.actual.getFirstZonedDateTime(name))
.as("check primary date value for HTTP header '%s'", name)
.isCloseTo(ZonedDateTime.ofInstant(value, GMT), Assertions.within(999, ChronoUnit.MILLIS));
.isCloseTo(value.atZone(GMT), Assertions.within(999, ChronoUnit.MILLIS));
return this.myself;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Map;

Expand Down Expand Up @@ -263,7 +263,7 @@ void testAcceptCharset() {
@Test
void testIfModifiedSince() {
RestTestClientTests.this.client.get().uri("/test")
.ifModifiedSince(ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.of("GMT")))
.ifModifiedSince(ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC))
.exchange()
.expectStatus().isOk()
.expectBody().jsonPath("$.headers.If-Modified-Since").isEqualTo("Thu, 01 Jan 1970 00:00:00 GMT");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.springframework.test.web.servlet.result;

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -45,7 +45,7 @@ public class HeaderResultMatchersTests {
@Test // SPR-17330
public void matchDateFormattedWithHttpHeaders() throws Exception {

long epochMilli = ZonedDateTime.of(2018, 10, 5, 0, 0, 0, 0, ZoneId.of("GMT")).toInstant().toEpochMilli();
long epochMilli = ZonedDateTime.of(2018, 10, 5, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();
HttpHeaders headers = new HttpHeaders();
headers.setDate("myDate", epochMilli);
this.response.setHeader("d", headers.getFirst("myDate"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package org.springframework.test.web.support;

import java.net.URI;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -272,7 +272,7 @@ void contentType() {
@Test
void expires() {
HttpHeaders headers = new HttpHeaders();
ZonedDateTime expires = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
ZonedDateTime expires = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
headers.setExpires(expires);
TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.expires(expires.toInstant().toEpochMilli());
Expand All @@ -285,7 +285,7 @@ void expires() {
@Test
void lastModified() {
HttpHeaders headers = new HttpHeaders();
ZonedDateTime lastModified = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
ZonedDateTime lastModified = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
headers.setLastModified(lastModified.toInstant().toEpochMilli());
TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.lastModified(lastModified.toInstant().toEpochMilli());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -414,7 +415,7 @@ public class HttpHeaders implements Serializable {

private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = new DecimalFormatSymbols(Locale.ROOT);

private static final ZoneId GMT = ZoneId.of("GMT");
private static final ZoneId GMT = ZoneOffset.UTC;

/**
* Date formats with time zone as specified in the HTTP RFC to use for formatting.
Expand Down Expand Up @@ -1516,7 +1517,7 @@ public void setZonedDateTime(String headerName, ZonedDateTime date) {
* @since 5.1.4
*/
public void setInstant(String headerName, Instant date) {
setZonedDateTime(headerName, ZonedDateTime.ofInstant(date, GMT));
setZonedDateTime(headerName, date.atZone(GMT));
}

/**
Expand Down Expand Up @@ -2172,7 +2173,7 @@ private static MultiValueMap<String, String> unwrap(HttpHeaders headers) {
// Package-private: used in ResponseCookie
static String formatDate(long date) {
Instant instant = Instant.ofEpochMilli(date);
ZonedDateTime time = ZonedDateTime.ofInstant(instant, GMT);
ZonedDateTime time = instant.atZone(GMT);
return DATE_FORMATTER.format(time);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Iterator;
Expand Down Expand Up @@ -51,7 +50,7 @@ public class InMemoryWebSessionStore implements WebSessionStore {

private int maxSessions = 10000;

private Clock clock = Clock.system(ZoneId.of("GMT"));
private Clock clock = Clock.systemUTC();

private final Map<String, InMemoryWebSession> sessions = new ConcurrentHashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -370,7 +370,7 @@ void expiresLong() {

@Test
void expiresZonedDateTime() {
ZonedDateTime zonedDateTime = ZonedDateTime.of(2008, 12, 18, 10, 20, 0, 0, ZoneId.of("GMT"));
ZonedDateTime zonedDateTime = ZonedDateTime.of(2008, 12, 18, 10, 20, 0, 0, ZoneOffset.UTC);
headers.setExpires(zonedDateTime);
assertThat(headers.getExpires()).as("Invalid Expires header").isEqualTo(zonedDateTime.toInstant().toEpochMilli());
assertThat(headers.getFirst("expires")).as("Invalid Expires header").isEqualTo("Thu, 18 Dec 2008 10:20:00 GMT");
Expand Down Expand Up @@ -605,7 +605,7 @@ void firstDate() {

@Test
void firstZonedDateTime() {
ZonedDateTime date = ZonedDateTime.of(2017, 6, 2, 2, 22, 0, 0, ZoneId.of("GMT"));
ZonedDateTime date = ZonedDateTime.of(2017, 6, 2, 2, 22, 0, 0, ZoneOffset.UTC);
headers.setZonedDateTime(HttpHeaders.DATE, date);
assertThat(headers.getFirst(HttpHeaders.DATE)).isEqualTo("Fri, 02 Jun 2017 02:22:00 GMT");
assertThat(headers.getFirstZonedDateTime(HttpHeaders.DATE).isEqual(date)).isTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
Expand Down Expand Up @@ -184,7 +184,7 @@ void cancelResponseBody(ClientHttpConnector connector) {

@ParameterizedConnectorTest
void cookieExpireValueSetAsMaxAge(ClientHttpConnector connector) {
ZonedDateTime tomorrow = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(1);
ZonedDateTime tomorrow = ZonedDateTime.now(ZoneOffset.UTC).plusDays(1);
String formattedDate = tomorrow.format(DateTimeFormatter.RFC_1123_DATE_TIME);

prepareResponse(builder -> builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package org.springframework.web.server.i18n;

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Locale;
import java.util.TimeZone;

Expand Down Expand Up @@ -61,7 +61,7 @@ void resolveCustomizedLocale() {

@Test
void resolveCustomizedAndTimeZoneLocale() {
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("UTC"));
TimeZone timeZone = TimeZone.getTimeZone(ZoneOffset.UTC);
Copy link
Author

@Pankraz76 Pankraz76 Nov 21, 2025

Choose a reason for hiding this comment

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

this seems a good thing to consider, being straight up instead of "error prone".

Copy link

Choose a reason for hiding this comment

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

What do you mean?

Copy link
Author

Choose a reason for hiding this comment

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

sorry i meant this is a good thing and seems easy consider suggest, as it avoids error prone (random) string.

FixedLocaleContextResolver resolver = new FixedLocaleContextResolver(FRANCE, timeZone);
TimeZoneAwareLocaleContext context = (TimeZoneAwareLocaleContext) resolver.resolveLocaleContext(exchange());
assertThat(context.getLocale()).isEqualTo(FRANCE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -165,7 +164,7 @@ void writeTo() {
RenderingResponse renderingResponse = RenderingResponse.create("view")
.status(HttpStatus.FOUND)
.modelAttributes(model)
.build().block(Duration.of(5, ChronoUnit.MILLIS));
.build().block(Duration.ofMillis(5));
assertThat(renderingResponse).isNotNull();

MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://localhost"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -97,7 +98,7 @@
*/
class HttpEntityMethodProcessorMockTests {

private static final ZoneId GMT = ZoneId.of("GMT");
private static final ZoneId GMT = ZoneOffset.UTC;


private HttpEntityMethodProcessor processor;
Expand Down