diff --git a/.gitattributes b/.gitattributes index fcadb2cf9..9cf876051 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,14 @@ -* text eol=lf +# Normalize text files to LF, but let Git auto-detect binaries so they are +# stored byte-for-byte (a blanket "* text" corrupts binaries like the Gradle +# wrapper jar by stripping CR bytes during line-ending normalization). +* text=auto eol=lf + +# Always treat these as binary regardless of auto-detection. +*.jar binary +*.zip binary +*.gz binary +*.class binary +*.png binary +*.jpg binary +*.gif binary +*.ico binary diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 5eb62cc47..cb9c6af53 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -29,11 +29,11 @@ jobs: exit 1 fi - - name: Setup java 17 for building + - name: Setup java 25 for building uses: actions/setup-java@v5 with: distribution: temurin - java-version: '17' + java-version: '25' - name: Set environment variables on Ubuntu if: matrix.os == 'ubuntu-latest' @@ -59,7 +59,7 @@ jobs: ./gradlew.bat build - name: Setup java ${{ matrix.java-version }} for testing - if: matrix.java-version != '17' + if: matrix.java-version != '25' uses: actions/setup-java@v5 with: distribution: temurin @@ -69,20 +69,20 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | cd functional - curl -sSfLO https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.11.4/junit-platform-console-standalone-1.11.4.jar - curl -sSfLO https://repo1.maven.org/maven2/com/github/spotbugs/spotbugs-annotations/4.9.8/spotbugs-annotations-4.9.8.jar - javac -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:../adminapi/build/libs/minio-admin-${DEV_VERSION}-all.jar:. FunctionalTest.java - java -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:../adminapi/build/libs/minio-admin-${DEV_VERSION}-all.jar:. FunctionalTest - javac -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:. ./TestUserAgent.java - java -Dversion=${DEV_VERSION} -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:. TestUserAgent - javac -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${RELEASE_VERSION}-all.jar:. ./TestUserAgent.java - java -Dversion=${RELEASE_VERSION} -cp spotbugs-annotations-4.9.8.jar:junit-platform-console-standalone-1.11.4.jar:../api/build/libs/minio-${RELEASE_VERSION}-all.jar:. TestUserAgent + curl -sSfLO https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.14.4/junit-platform-console-standalone-1.14.4.jar + curl -sSfLO https://repo1.maven.org/maven2/com/github/spotbugs/spotbugs-annotations/4.10.2/spotbugs-annotations-4.10.2.jar + javac -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:../adminapi/build/libs/minio-admin-${DEV_VERSION}-all.jar:. FunctionalTest.java + java -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:../adminapi/build/libs/minio-admin-${DEV_VERSION}-all.jar:. FunctionalTest + javac -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:. ./TestUserAgent.java + java -Dversion=${DEV_VERSION} -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${DEV_VERSION}-all.jar:. TestUserAgent + javac -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${RELEASE_VERSION}-all.jar:. ./TestUserAgent.java + java -Dversion=${RELEASE_VERSION} -cp spotbugs-annotations-4.10.2.jar:junit-platform-console-standalone-1.14.4.jar:../api/build/libs/minio-${RELEASE_VERSION}-all.jar:. TestUserAgent - name: Run tests on Windows if: matrix.os == 'windows-latest' run: | cd functional - curl -sSfLO https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.11.4/junit-platform-console-standalone-1.11.4.jar - curl -sSfLO https://repo1.maven.org/maven2/com/github/spotbugs/spotbugs-annotations/4.9.8/spotbugs-annotations-4.9.8.jar - javac -encoding UTF-8 -cp "spotbugs-annotations-4.9.8.jar;junit-platform-console-standalone-1.11.4.jar;../api/build/libs/minio-$Env:DEV_VERSION-all.jar;../adminapi/build/libs/minio-admin-$Env:DEV_VERSION-all.jar;." FunctionalTest.java - java -cp "spotbugs-annotations-4.9.8.jar;junit-platform-console-standalone-1.11.4.jar;../api/build/libs/minio-$Env:DEV_VERSION-all.jar;../adminapi/build/libs/minio-admin-$Env:DEV_VERSION-all.jar;." FunctionalTest + curl -sSfLO https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.14.4/junit-platform-console-standalone-1.14.4.jar + curl -sSfLO https://repo1.maven.org/maven2/com/github/spotbugs/spotbugs-annotations/4.10.2/spotbugs-annotations-4.10.2.jar + javac -encoding UTF-8 -cp "spotbugs-annotations-4.10.2.jar;junit-platform-console-standalone-1.14.4.jar;../api/build/libs/minio-$Env:DEV_VERSION-all.jar;../adminapi/build/libs/minio-admin-$Env:DEV_VERSION-all.jar;." FunctionalTest.java + java -cp "spotbugs-annotations-4.10.2.jar;junit-platform-console-standalone-1.14.4.jar;../api/build/libs/minio-$Env:DEV_VERSION-all.jar;../adminapi/build/libs/minio-admin-$Env:DEV_VERSION-all.jar;." FunctionalTest diff --git a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java index e5588d1bc..e6e702e39 100644 --- a/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java +++ b/adminapi/src/main/java/io/minio/admin/MinioAdminClient.java @@ -453,8 +453,10 @@ public long getBucketQuota(String bucketName) throws MinioException { OBJECT_MAPPER .getTypeFactory() .constructMapType(HashMap.class, String.class, JsonNode.class); - return OBJECT_MAPPER.>readValue(response.body().bytes(), mapType) - .entrySet().stream() + return OBJECT_MAPPER + .>readValue(response.body().bytes(), mapType) + .entrySet() + .stream() .filter(entry -> "quota".equals(entry.getKey())) .findFirst() .map(entry -> Long.valueOf(entry.getValue().toString())) diff --git a/api/src/main/java/io/minio/Checksum.java b/api/src/main/java/io/minio/Checksum.java index 75c048b96..d1d15cb90 100644 --- a/api/src/main/java/io/minio/Checksum.java +++ b/api/src/main/java/io/minio/Checksum.java @@ -33,6 +33,7 @@ public class Checksum { /** MD5 hash of zero length byte array. */ public static final String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg=="; + /** SHA-256 hash of zero length byte array. */ public static final String ZERO_SHA256_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; diff --git a/api/src/main/java/io/minio/Http.java b/api/src/main/java/io/minio/Http.java index 772ba721d..e6b6ac669 100644 --- a/api/src/main/java/io/minio/Http.java +++ b/api/src/main/java/io/minio/Http.java @@ -890,7 +890,7 @@ public static OkHttpClient setTimeout( .build(); } - /** HTTP body of {@link RandomAccessFile}, {@link ByteBuffer} or {@link byte} array. */ + /** HTTP body of {@link RandomAccessFile}, {@link ByteBuffer} or {@code byte} array. */ public static class Body { private okhttp3.RequestBody requestBody; private RandomAccessFile file; diff --git a/api/src/main/java/io/minio/PartReader.java b/api/src/main/java/io/minio/PartReader.java index 1eb03e208..6715f65ea 100644 --- a/api/src/main/java/io/minio/PartReader.java +++ b/api/src/main/java/io/minio/PartReader.java @@ -96,7 +96,8 @@ private void readOneByte() throws MinioException { int n = 0; try { - while ((n = file != null ? file.read(oneByte) : stream.read(oneByte)) == 0) ; + while ((n = file != null ? file.read(oneByte) : stream.read(oneByte)) == 0) + ; } catch (IOException e) { throw new MinioException(e); } diff --git a/api/src/main/java/io/minio/errors/MinioException.java b/api/src/main/java/io/minio/errors/MinioException.java index 31f3be597..2ec209d04 100644 --- a/api/src/main/java/io/minio/errors/MinioException.java +++ b/api/src/main/java/io/minio/errors/MinioException.java @@ -62,12 +62,26 @@ public String httpTrace() { /** Throws encapsulated exception. */ public void throwEncapsulatedException() - throws BucketPolicyTooLargeException, CertificateException, EOFException, - ErrorResponseException, FileNotFoundException, GeneralSecurityException, - InsufficientDataException, InternalException, InvalidKeyException, - InvalidResponseException, IOException, JsonMappingException, JsonParseException, - JsonProcessingException, KeyManagementException, KeyStoreException, MinioException, - NoSuchAlgorithmException, ServerException, XmlParserException { + throws BucketPolicyTooLargeException, + CertificateException, + EOFException, + ErrorResponseException, + FileNotFoundException, + GeneralSecurityException, + InsufficientDataException, + InternalException, + InvalidKeyException, + InvalidResponseException, + IOException, + JsonMappingException, + JsonParseException, + JsonProcessingException, + KeyManagementException, + KeyStoreException, + MinioException, + NoSuchAlgorithmException, + ServerException, + XmlParserException { Throwable e = getCause(); // Inherited by MinioException diff --git a/build.gradle b/build.gradle index dedf232cc..28649990d 100644 --- a/build.gradle +++ b/build.gradle @@ -15,14 +15,14 @@ */ /********************************/ -/* gradleVersion = '9.4.1' */ +/* gradleVersion = '9.6.0' */ /********************************/ plugins { - id 'com.gradleup.shadow' version '9.0.0' - id 'com.github.spotbugs' version '6.5.1' - id 'org.jreleaser' version '1.23.0' - id 'com.diffplug.spotless' version '6.13.0' + id 'com.gradleup.shadow' version '9.4.2' + id 'com.github.spotbugs' version '6.5.8' + id 'org.jreleaser' version '1.24.0' + id 'com.diffplug.spotless' version '8.7.0' } /* Root project definitions */ @@ -48,22 +48,26 @@ subprojects { dependencies { api 'com.carrotsearch.thirdparty:simple-xml-safe:2.7.1' api 'com.google.guava:guava:33.6.0-jre' - api 'com.squareup.okhttp3:okhttp:5.3.2' - api 'com.fasterxml.jackson.core:jackson-annotations:2.21' - api 'com.fasterxml.jackson.core:jackson-core:2.21.2' - api 'com.fasterxml.jackson.core:jackson-databind:2.21.2' + api 'com.squareup.okhttp3:okhttp:5.4.0' + api 'com.fasterxml.jackson.core:jackson-annotations:2.22' + api 'com.fasterxml.jackson.core:jackson-core:2.22.0' + api 'com.fasterxml.jackson.core:jackson-databind:2.22.0' api 'org.bouncycastle:bcprov-jdk18on:1.84' api 'org.apache.commons:commons-compress:1.28.0' - api 'commons-codec:commons-codec:1.21.0' + api 'commons-codec:commons-codec:1.22.0' api 'org.xerial.snappy:snappy-java:1.1.10.8' - compileOnly 'com.github.spotbugs:spotbugs-annotations:4.9.8' + compileOnly 'com.github.spotbugs:spotbugs-annotations:4.10.2' - testImplementation 'com.squareup.okhttp3:mockwebserver:5.3.2' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.14.3' + testImplementation 'com.squareup.okhttp3:mockwebserver:5.4.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.14.4' } [compileJava, compileTestJava].each() { it.options.fork = true + // Build runs on JDK 25 (see java.toolchain) but enforces the Java 8 API surface and + // emits Java 8 bytecode via --release 8. --release also avoids the "source/target 8 is + // obsolete" warning; -Xlint:-options is kept as a belt-and-braces guard for -Werror. + it.options.release = 8 it.options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation', '-Xlint:-options', '-Werror', '-Xdiags:verbose'] it.options.encoding = 'UTF-8' } @@ -103,6 +107,10 @@ subprojects { check.dependsOn localeTest java { + // Compile/test/javadoc run on JDK 25; bytecode/API level pinned to Java 8 via release below. + toolchain { + languageVersion = JavaLanguageVersion.of(25) + } sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } @@ -112,7 +120,7 @@ subprojects { target '**/*.java' importOrder 'edu', 'com', 'io', 'java', 'javax', 'org', '' removeUnusedImports() - googleJavaFormat('1.7') + googleJavaFormat('1.35.0') } groovyGradle { target '*.gradle' @@ -226,7 +234,7 @@ project(':api') { } signing { - required { + required = { gradle.taskGraph.allTasks.any { it.name.contains('LocalMavenWithChecksums') } } sign publishing.publications.minioJava @@ -346,7 +354,7 @@ project(':adminapi') { } signing { - required { + required = { gradle.taskGraph.allTasks.any { it.name.contains('LocalMavenWithChecksums') } } sign publishing.publications.minioJava @@ -355,7 +363,7 @@ project(':adminapi') { project(':examples') { dependencies { - compileOnly 'me.tongfei:progressbar:0.9.5' + compileOnly 'me.tongfei:progressbar:0.10.2' compileOnly project(':api') } @@ -367,6 +375,9 @@ project(':examples') { main { java { srcDirs = ["$rootDir/examples"] + // srcDir is the module root, which also contains build/; keep generated + // files (e.g. Spotless lint output) out of compilation. + exclude 'build/**' } } } @@ -374,7 +385,7 @@ project(':examples') { project(':functional') { dependencies { - implementation 'org.junit.jupiter:junit-jupiter-api:5.14.3' + implementation 'org.junit.jupiter:junit-jupiter-api:5.14.4' implementation project(':api') implementation project(':adminapi') } @@ -387,6 +398,9 @@ project(':functional') { main { java { srcDirs = ["$rootDir/functional"] + // srcDir is the module root, which also contains build/; keep generated + // files (e.g. Spotless lint output) out of compilation. + exclude 'build/**' } } } diff --git a/functional/TestMinioClient.java b/functional/TestMinioClient.java index 28182b3c2..86769bac0 100644 --- a/functional/TestMinioClient.java +++ b/functional/TestMinioClient.java @@ -548,7 +548,9 @@ public void putObject() throws Exception { testPutObject( "[object name ends with '/']", - PutObjectArgs.builder().bucket(bucketName).object("path/to/" + getRandomName() + "/") + PutObjectArgs.builder() + .bucket(bucketName) + .object("path/to/" + getRandomName() + "/") .stream(new ContentInputStream(0), 0L, null) .contentType(CUSTOM_CONTENT_TYPE) .build(), @@ -1445,7 +1447,9 @@ public void testCopyObject( client.makeBucket(MakeBucketArgs.builder().bucket(args.source().bucket()).build()); try { PutObjectArgs.Builder builder = - PutObjectArgs.builder().bucket(args.source().bucket()).object(args.source().object()) + PutObjectArgs.builder() + .bucket(args.source().bucket()) + .object(args.source().object()) .stream(new ContentInputStream(1 * KB), 1L * KB, null); if (sse != null) builder.sse(sse); client.putObject(builder.build()); diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b953..b1b8ef56b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118f7..eb84db68d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index f3b75f3b0..249efbb03 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -205,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a2183..a51ec4f58 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,12 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/spotbugs-filter.xml b/spotbugs-filter.xml index bc8accf49..27f43ade6 100644 --- a/spotbugs-filter.xml +++ b/spotbugs-filter.xml @@ -32,4 +32,8 @@ + + + +