diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b11db2b271d..a511432de89 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -32,7 +32,7 @@ updates: interval: "weekly" day: "sunday" ignore: - # Jetty >= 10 requires JDK 11 + # Jetty >= 10 uses the Jakarta Servlet API; upgrading requires a javax -> jakarta migration - dependency-name: "org.eclipse.jetty:jetty-server" versions: - ">= 10.0.0" diff --git a/.github/workflows/codeql-java-analysis.yml b/.github/workflows/codeql-java-analysis.yml index b7668b497fd..c532576696b 100644 --- a/.github/workflows/codeql-java-analysis.yml +++ b/.github/workflows/codeql-java-analysis.yml @@ -70,15 +70,14 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main queries: +security-and-quality - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index f456026f505..a13067a1432 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -155,9 +155,9 @@ jobs: with: distribution: 'temurin' java-version: | - 11 17 21 + 25 - name: Build Java docs run: | diff --git a/.github/workflows/java-publish-snapshot.yml b/.github/workflows/java-publish-snapshot.yml index c20d218e19e..d2bdbb5d9be 100644 --- a/.github/workflows/java-publish-snapshot.yml +++ b/.github/workflows/java-publish-snapshot.yml @@ -43,15 +43,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/maven4.yml b/.github/workflows/maven4.yml index f19c6dcd355..7adbaeb20f8 100644 --- a/.github/workflows/maven4.yml +++ b/.github/workflows/maven4.yml @@ -50,15 +50,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven-build-cache - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: Setup Maven 4 uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/rat.yml b/.github/workflows/rat.yml index 96a9c0ec915..763d5f0ddc8 100644 --- a/.github/workflows/rat.yml +++ b/.github/workflows/rat.yml @@ -39,15 +39,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/spotless.yml b/.github/workflows/spotless.yml index 2b4f8bdedf8..410652f5486 100644 --- a/.github/workflows/spotless.yml +++ b/.github/workflows/spotless.yml @@ -42,15 +42,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-c.yml b/.github/workflows/test-lang-c.yml index e3afece7c55..fb7e3531d6f 100644 --- a/.github/workflows/test-lang-c.yml +++ b/.github/workflows/test-lang-c.yml @@ -68,15 +68,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 @@ -128,15 +127,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-csharp.yml b/.github/workflows/test-lang-csharp.yml index af5ddbc8e0c..1c2223115be 100644 --- a/.github/workflows/test-lang-csharp.yml +++ b/.github/workflows/test-lang-csharp.yml @@ -98,15 +98,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-java.yml b/.github/workflows/test-lang-java.yml index 97d5111692f..ffdce7ef044 100644 --- a/.github/workflows/test-lang-java.yml +++ b/.github/workflows/test-lang-java.yml @@ -54,14 +54,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: "Setup Temurin JDK 11, 17 & 21" + - name: "Setup Temurin JDK 17, 21 & 25" uses: actions/setup-java@v5 with: distribution: "temurin" java-version: | - 11 17 21 + 25 - name: "Setup Maven 3.9.11" uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 @@ -106,14 +106,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: "Setup Temurin JDK 11, 17 & 21" + - name: "Setup Temurin JDK 17, 21 & 25" uses: actions/setup-java@v5 with: distribution: "temurin" java-version: | - 11 17 21 + 25 - name: "Setup Maven 3.9.11" uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 @@ -164,10 +164,10 @@ jobs: working-directory: . run: mvn -B install -PskipQuality - - name: "Generate Interop Data using Java 11, 17 & 21" + - name: "Generate Interop Data using Java 17, 21 & 25" working-directory: lang/java/interop-data-test run: mvn -B verify -Pgenerate-test-data - - name: "Run Interop Tests using Java 11, 17 & 21" + - name: "Run Interop Tests using Java 17, 21 & 25" working-directory: lang/java/interop-data-test run: mvn -B verify -Pcheck-test-data diff --git a/.github/workflows/test-lang-perl.yml b/.github/workflows/test-lang-perl.yml index b92a13f1855..76bd16cd236 100644 --- a/.github/workflows/test-lang-perl.yml +++ b/.github/workflows/test-lang-perl.yml @@ -113,15 +113,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-php.yml b/.github/workflows/test-lang-php.yml index 4359f609dd6..32133d40484 100644 --- a/.github/workflows/test-lang-php.yml +++ b/.github/workflows/test-lang-php.yml @@ -109,15 +109,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-py.yml b/.github/workflows/test-lang-py.yml index 1db39c4e069..6c11b505b31 100644 --- a/.github/workflows/test-lang-py.yml +++ b/.github/workflows/test-lang-py.yml @@ -127,15 +127,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: "Setup Temurin JDK 8, 11, 17 & 21" + - name: "Setup Temurin JDK 17, 21 & 25" uses: actions/setup-java@v5 with: distribution: "temurin" java-version: | - 8 - 11 17 21 + 25 - name: "Setup Maven 3.9.11" uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/.github/workflows/test-lang-ruby.yml b/.github/workflows/test-lang-ruby.yml index bf98f9ccb78..fc30937641c 100644 --- a/.github/workflows/test-lang-ruby.yml +++ b/.github/workflows/test-lang-ruby.yml @@ -117,15 +117,14 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: 'Setup Temurin JDK 8, 11, 17 & 21' + - name: 'Setup Temurin JDK 17, 21 & 25' uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: | - 8 - 11 17 21 + 25 - name: 'Setup Maven 3.9.11' uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 diff --git a/doc/content/en/docs/++version++/Getting started (Java)/_index.md b/doc/content/en/docs/++version++/Getting started (Java)/_index.md index 44aeae4767d..bf1acc01fc4 100644 --- a/doc/content/en/docs/++version++/Getting started (Java)/_index.md +++ b/doc/content/en/docs/++version++/Getting started (Java)/_index.md @@ -69,8 +69,8 @@ As well as the Avro Maven plugin (for performing code generation): org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 17 + 17 ``` diff --git a/doc/examples/java-example/pom.xml b/doc/examples/java-example/pom.xml index 2fb9ba89d36..5d29ef13bfe 100644 --- a/doc/examples/java-example/pom.xml +++ b/doc/examples/java-example/pom.xml @@ -49,8 +49,7 @@ maven-compiler-plugin 3.8.1 - 11 - 11 + 17 diff --git a/doc/examples/mr-example/pom.xml b/doc/examples/mr-example/pom.xml index 089adf79764..400dc4e102a 100644 --- a/doc/examples/mr-example/pom.xml +++ b/doc/examples/mr-example/pom.xml @@ -39,8 +39,7 @@ maven-compiler-plugin 3.8.1 - 11 - 11 + 17 diff --git a/lang/java/archetypes/avro-service-archetype/src/main/pom/pom.xml b/lang/java/archetypes/avro-service-archetype/src/main/pom/pom.xml index be2717556a5..76724867d7c 100644 --- a/lang/java/archetypes/avro-service-archetype/src/main/pom/pom.xml +++ b/lang/java/archetypes/avro-service-archetype/src/main/pom/pom.xml @@ -33,7 +33,6 @@ Simple Avro Ordering Service - ${maven.compiler.source} ${maven.compiler.release} ${project.build.sourceEncoding} ${project.version} @@ -141,7 +140,6 @@ org.apache.maven.plugins maven-compiler-plugin - \${maven.compiler.source} \${maven.compiler.release} diff --git a/lang/java/avro/pom.xml b/lang/java/avro/pom.xml index 8cab8b75f5c..7df974d1605 100644 --- a/lang/java/avro/pom.xml +++ b/lang/java/avro/pom.xml @@ -154,50 +154,50 @@ - Run all tests under Java 11 + Run all tests under Java 17 run - [11,12) + [17,18) - 11 + 17 - ${project.build.directory}/it-jdk-11 + ${project.build.directory}/it-jdk-17 - Run all tests under Java 17 + Run all tests under Java 21 run - [17,18) + [21,22) - 17 + 21 - ${project.build.directory}/it-jdk-17 + ${project.build.directory}/it-jdk-21 - Run all tests under Java 21 + Run all tests under Java 25 run - [21,22) + [25,26) - 21 + 25 - ${project.build.directory}/it-jdk-21 + ${project.build.directory}/it-jdk-25 diff --git a/lang/java/avro/src/it/pom.xml b/lang/java/avro/src/it/pom.xml index bd9bc523d7a..86868358c47 100644 --- a/lang/java/avro/src/it/pom.xml +++ b/lang/java/avro/src/it/pom.xml @@ -30,7 +30,7 @@ UTF-8 UTF-8 - 8 + 17 diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java index 61e070b0525..a1158b2427d 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java +++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java @@ -69,8 +69,6 @@ /** Utilities to use existing Java classes and interfaces via reflection. */ public class ReflectData extends SpecificData { - private static final String STRING_OUTER_PARENT_REFERENCE = "this$0"; - // holds a wrapper so null entries will have a cached value private final ConcurrentMap encoderCache = new ConcurrentHashMap<>(); @@ -741,6 +739,9 @@ protected Schema createSchema(Type type, Map names) { schema = Schema.createRecord(name, doc, space, error); consumeAvroAliasAnnotation(c, schema); names.put(fullName, schema); + if (c.isMemberClass() && !Modifier.isStatic(c.getModifiers())) { + throw new AvroTypeException("Class " + fullName + " must be a static inner class"); + } for (Field field : getCachedFields(c)) if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0 && !field.isAnnotationPresent(AvroIgnore.class)) { @@ -752,9 +753,6 @@ protected Schema createSchema(Type type, Map names) { AvroName annotatedName = field.getAnnotation(AvroName.class); // Rename fields String fieldName = (annotatedName != null) ? annotatedName.value() : field.getName(); - if (STRING_OUTER_PARENT_REFERENCE.equals(fieldName)) { - throw new AvroTypeException("Class " + fullName + " must be a static inner class"); - } Schema.Field recordField = new Schema.Field(fieldName, fieldSchema, doc, defaultValue); AvroMeta[] metadata = field.getAnnotationsByType(AvroMeta.class); // add metadata diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectionUtil.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectionUtil.java index 3221d91d1f2..f391d9a3aaf 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectionUtil.java +++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectionUtil.java @@ -34,11 +34,7 @@ import java.util.function.Supplier; /** - * A few utility methods for using @link{java.misc.Unsafe}, mostly for private - * use. - * - * Use of Unsafe on Android is forbidden, as Android provides only a very - * limited functionality for this class compared to the JDK version. + * Utility methods for reflective field access. * * InterfaceAudience.Private */ diff --git a/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java b/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java deleted file mode 100644 index 394aa2b3a63..00000000000 --- a/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.avro.util; - -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; - -public class MapUtil { - - private MapUtil() { - super(); - } - - /** - * A temporary workaround for Java 8 specific performance issue JDK-8161372. - * - * @see JDK-8161372 - * @deprecated As of JDK 1.9 this issue has been resolved. - */ - // TODO: Remove for 1.13.0 or later - @Deprecated - public static V computeIfAbsent(ConcurrentMap map, K key, Function mappingFunction) { - V value = map.get(key); - if (value != null) { - return value; - } - return map.computeIfAbsent(key, mappingFunction::apply); - } - -} diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestBigDecimalConversion.java b/lang/java/avro/src/test/java/org/apache/avro/TestBigDecimalConversion.java index e781fe07bd9..0913b1fd056 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestBigDecimalConversion.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestBigDecimalConversion.java @@ -19,7 +19,6 @@ package org.apache.avro; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestProtocol.java b/lang/java/avro/src/test/java/org/apache/avro/TestProtocol.java index cc59a6cd996..7d543a35dac 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestProtocol.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestProtocol.java @@ -17,24 +17,11 @@ */ package org.apache.avro; -import org.apache.avro.generic.GenericData; -import org.apache.avro.generic.GenericDatumWriter; -import org.apache.avro.generic.IndexedRecord; -import org.apache.avro.io.EncoderFactory; -import org.apache.avro.io.JsonEncoder; - -import com.fasterxml.jackson.databind.JsonNode; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.*; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.util.Collections; import org.junit.jupiter.api.Test; diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityEnumDefaults.java b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityEnumDefaults.java index 44d468c7dea..0f050b59c47 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityEnumDefaults.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityEnumDefaults.java @@ -27,7 +27,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.ByteArrayOutputStream; -import java.util.concurrent.Callable; import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericDatumReader; diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityMissingUnionBranch.java b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityMissingUnionBranch.java index 3e84a5337c9..6b4bc26624f 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityMissingUnionBranch.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaCompatibilityMissingUnionBranch.java @@ -22,9 +22,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Collections; import java.util.List; diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestUnionError.java b/lang/java/avro/src/test/java/org/apache/avro/TestUnionError.java index d5847ba36a9..dbdc4bcb78e 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/TestUnionError.java +++ b/lang/java/avro/src/test/java/org/apache/avro/TestUnionError.java @@ -23,7 +23,6 @@ import org.apache.avro.generic.GenericRecord; import org.apache.avro.io.BinaryDecoder; import org.apache.avro.io.BinaryEncoder; -import org.apache.avro.io.DatumReader; import org.apache.avro.io.DecoderFactory; import org.apache.avro.io.EncoderFactory; diff --git a/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java b/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java index caf485500f0..e0221848745 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java +++ b/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java @@ -23,7 +23,6 @@ import org.apache.avro.generic.GenericDatumReader; import org.apache.avro.message.BinaryMessageDecoder; import org.apache.avro.specific.TestRecordWithMapsAndArrays; -import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; @@ -33,7 +32,6 @@ import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; diff --git a/lang/java/avro/src/test/java/org/apache/avro/io/TestEncoders.java b/lang/java/avro/src/test/java/org/apache/avro/io/TestEncoders.java index df4ca4aeb02..24ad7bada08 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/io/TestEncoders.java +++ b/lang/java/avro/src/test/java/org/apache/avro/io/TestEncoders.java @@ -33,7 +33,6 @@ import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -42,7 +41,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import static java.util.Arrays.asList; diff --git a/lang/java/java17-test/src/test/java/org/apache/avro/reflect/TestJavaRecords.java b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestJavaRecords.java similarity index 100% rename from lang/java/java17-test/src/test/java/org/apache/avro/reflect/TestJavaRecords.java rename to lang/java/avro/src/test/java/org/apache/avro/reflect/TestJavaRecords.java diff --git a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java index cf0e99756eb..a2ae0ab7cf1 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java +++ b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java @@ -40,7 +40,6 @@ import org.apache.avro.AvroTypeException; import org.apache.avro.JsonProperties; import org.apache.avro.JsonSchemaParser; -import org.apache.avro.NameValidator; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.Schema.Field; @@ -55,8 +54,6 @@ import org.apache.avro.util.Utf8; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; public class TestReflect { @@ -1211,30 +1208,11 @@ public static void checkBinary(Schema schema, Object datum) throws IOException { /** Test that the error message contains the name of the class. */ @Test - @EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_11, disabledReason = "Java 11 announced: All illegal access operations will be denied in a future release") - // Java 11: - // - WARNING: An illegal reflective access operation has occurred - // - WARNING: Illegal reflective access by - // org.apache.avro.reflect.FieldAccessReflect$ReflectionBasedAccessor to field - // java.lang.String.coder - // - WARNING: Please consider reporting this to the maintainers of - // org.apache.avro.reflect.FieldAccessReflect$ReflectionBasedAccessor - // - WARNING: Use --illegal-access=warn to enable warnings of further illegal - // reflective access operations - // - WARNING: All illegal access operations will be denied in a future release - // Java 17: - // - [ERROR] org.apache.avro.reflect.TestReflect.reflectFieldError -- Time - // elapsed: 0.015 s <<< ERROR! - // - java.lang.reflect.InaccessibleObjectException: Unable to make field private - // final byte java.lang.String.coder accessible: module java.base does not - // "opens java.lang" to unnamed module @5a6d67c3 void reflectFieldError() throws Exception { Object datum = ""; - try { + assertThrows(java.lang.reflect.InaccessibleObjectException.class, () -> { ReflectData.get().getField(datum, "notAFieldOfString", 0); - } catch (AvroRuntimeException e) { - assertTrue(e.getMessage().contains(datum.getClass().getName())); - } + }); } @AvroAlias(alias = "a", space = "b") diff --git a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectData.java b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectData.java index 40d9ad6decb..16328af58c4 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectData.java +++ b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectData.java @@ -19,14 +19,11 @@ package org.apache.avro.reflect; import org.apache.avro.AvroTypeException; -import org.apache.avro.JsonSchemaParser; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParser; import org.apache.avro.util.internal.JacksonUtils; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import java.util.Arrays; import java.util.Collections; @@ -144,8 +141,6 @@ public class Definition { } @Test - // FIXME: Why does this test fail under JDK 21? - @EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17, disabledReason = "Doesn't work under JRE 21, no clue why") void nonStaticInnerClasses() { assertThrows(AvroTypeException.class, () -> { ReflectData.get().getSchema(Definition.class); diff --git a/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java b/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java index 1ffe36b79d1..6287db1a1b9 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java +++ b/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java @@ -17,9 +17,6 @@ */ package org.apache.avro.specific; -import org.apache.avro.generic.GenericArray; -import org.apache.avro.specific.SpecificData; -import org.apache.avro.util.Utf8; import org.apache.avro.message.BinaryMessageEncoder; import org.apache.avro.message.BinaryMessageDecoder; import org.apache.avro.message.SchemaStore; diff --git a/lang/java/avro/src/test/java/org/apache/avro/specific/int$.java b/lang/java/avro/src/test/java/org/apache/avro/specific/int$.java index 2a1a1470f8f..1b01354263d 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/specific/int$.java +++ b/lang/java/avro/src/test/java/org/apache/avro/specific/int$.java @@ -5,7 +5,6 @@ */ package org.apache.avro.specific; -import com.fasterxml.jackson.databind.jsonschema.JsonSchema; import org.apache.avro.JsonSchemaParser; import org.apache.avro.message.BinaryMessageDecoder; import org.apache.avro.message.BinaryMessageEncoder; diff --git a/lang/java/build.sh b/lang/java/build.sh index 5020a6ed0ca..c72b93bf70e 100755 --- a/lang/java/build.sh +++ b/lang/java/build.sh @@ -33,8 +33,6 @@ main() { ;; test) mvn -B verify - # Test the modules that depend on hadoop using Hadoop 2 - mvn -Dmaven.build.cache.enabled=false -B test -Phadoop2 ;; dist) mvn -P dist package -DskipTests javadoc:aggregate diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index ea1e1a11b55..17d153bd429 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -1225,7 +1225,7 @@ public static String generateGetMethod(Schema schema, Field field) { } /** - * Generates the name of a field accessor method that returns a Java 8 Optional. + * Generates the name of a field accessor method that returns an Optional. * * @param schema the schema in which the field is defined. * @param field the field for which to generate the accessor name. diff --git a/lang/java/compiler/src/test/java/org/apache/avro/specific/TestSpecificData.java b/lang/java/compiler/src/test/java/org/apache/avro/specific/TestSpecificData.java index 33a9205e453..0d429f94b59 100644 --- a/lang/java/compiler/src/test/java/org/apache/avro/specific/TestSpecificData.java +++ b/lang/java/compiler/src/test/java/org/apache/avro/specific/TestSpecificData.java @@ -46,7 +46,6 @@ import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; -import org.apache.avro.JsonSchemaParser; import org.apache.avro.Schema; import org.apache.avro.SchemaParser; import org.apache.avro.compiler.specific.SpecificCompiler; @@ -86,23 +85,6 @@ void separateThreadContextClassLoader() throws Exception { StandardJavaFileManager fileManager = javac.getStandardFileManager(null, null, null); Iterable units = fileManager.getJavaFileObjects("target/foo/Bar.java"); - JavaCompiler.CompilationTask task1 = javac.getTask(null, fileManager, null, null, null, units); - - // FIXME: This part uses JavacTask which makes it depend on the tools.jar and - // thus will only run in JDK 8 - // JavacTask jcTask = (JavacTask) task1; - - // Iterable analyze = jcTask.analyze(); - - // GeneratedCodeController ctrl = new GeneratedCodeController(); - // for (Element el : analyze) { - // if (el.getKind() == ElementKind.CLASS) { - // List accept = el.accept(ctrl, 0); - // assertTrue(accept.isEmpty(), - // accept.stream().collect(Collectors.joining("\n\t"))); - // } - // } - javac.getTask(null, fileManager, null, null, null, units).call(); fileManager.close(); diff --git a/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java b/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java index bfb8ec2de7a..0984473546f 100644 --- a/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java +++ b/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java @@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentMap; import io.grpc.MethodDescriptor; -import org.apache.avro.util.MapUtil; import static io.grpc.MethodDescriptor.generateFullMethodName; @@ -50,7 +49,7 @@ private ServiceDescriptor(Class iface, String serviceName) { */ public static ServiceDescriptor create(Class iface) { String serviceName = AvroGrpcUtils.getServiceName(iface); - return MapUtil.computeIfAbsent(SERVICE_DESCRIPTORS, serviceName, key -> new ServiceDescriptor(iface, serviceName)); + return SERVICE_DESCRIPTORS.computeIfAbsent(serviceName, key -> new ServiceDescriptor(iface, serviceName)); } /** @@ -68,7 +67,7 @@ public String getServiceName() { * @return a {@link MethodDescriptor} */ public MethodDescriptor getMethod(String methodName, MethodDescriptor.MethodType methodType) { - return MapUtil.computeIfAbsent(methods, methodName, + return methods.computeIfAbsent(methodName, key -> MethodDescriptor.newBuilder() .setFullMethodName(generateFullMethodName(serviceName, methodName)).setType(methodType) .setRequestMarshaller(new AvroRequestMarshaller(protocol.getMessages().get(methodName))) diff --git a/lang/java/interop-data-test/pom.xml b/lang/java/interop-data-test/pom.xml index c691665ef2d..9f8cbdd0e72 100644 --- a/lang/java/interop-data-test/pom.xml +++ b/lang/java/interop-data-test/pom.xml @@ -69,50 +69,50 @@ - ${invoker-action} under Java 11 + ${invoker-action} under Java 17 run - [11,12) + [17,18) - 11 + 17 - ${project.build.directory}/it-jdk-11 + ${project.build.directory}/it-jdk-17 - ${invoker-action} under Java 17 + ${invoker-action} under Java 21 run - [17,18) + [21,22) - 17 + 21 - ${project.build.directory}/it-jdk-17 + ${project.build.directory}/it-jdk-21 - ${invoker-action} under Java 21 + ${invoker-action} under Java 25 run - [21,22) + [25,26) - 21 + 25 - ${project.build.directory}/it-jdk-21 + ${project.build.directory}/it-jdk-25 diff --git a/lang/java/interop-data-test/src/it/check/pom.xml b/lang/java/interop-data-test/src/it/check/pom.xml index 64eeaf4c850..ecb07b9fec1 100644 --- a/lang/java/interop-data-test/src/it/check/pom.xml +++ b/lang/java/interop-data-test/src/it/check/pom.xml @@ -30,7 +30,7 @@ UTF-8 UTF-8 - 11 + 17 ../../../../../.. ${main.basedir}/build/interop/data/ diff --git a/lang/java/interop-data-test/src/it/generate/pom.xml b/lang/java/interop-data-test/src/it/generate/pom.xml index c79dd35db0e..47741684c48 100644 --- a/lang/java/interop-data-test/src/it/generate/pom.xml +++ b/lang/java/interop-data-test/src/it/generate/pom.xml @@ -30,7 +30,7 @@ UTF-8 UTF-8 - 11 + 17 ../../../../../.. diff --git a/lang/java/ipc-netty/src/test/java/org/apache/avro/ipc/netty/TestNettyServerWithSSL.java b/lang/java/ipc-netty/src/test/java/org/apache/avro/ipc/netty/TestNettyServerWithSSL.java index aafdd4f607a..9b969002f1b 100644 --- a/lang/java/ipc-netty/src/test/java/org/apache/avro/ipc/netty/TestNettyServerWithSSL.java +++ b/lang/java/ipc-netty/src/test/java/org/apache/avro/ipc/netty/TestNettyServerWithSSL.java @@ -20,7 +20,6 @@ import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.KeyStore; import java.security.Security; diff --git a/lang/java/ipc/src/test/java/org/apache/avro/TestProtocolReflect.java b/lang/java/ipc/src/test/java/org/apache/avro/TestProtocolReflect.java index dd763444138..1b61553342c 100644 --- a/lang/java/ipc/src/test/java/org/apache/avro/TestProtocolReflect.java +++ b/lang/java/ipc/src/test/java/org/apache/avro/TestProtocolReflect.java @@ -28,8 +28,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import static org.junit.jupiter.api.Assertions.*; @@ -145,21 +143,6 @@ void echoBytes() throws IOException { assertArrayEquals(data, echoed); } - @Test - // The JRE range is because reflection based protocols try to (among others) - // make the field Throwable.cause accessible, and are not allowed to. - @EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_11, disabledReason = "Java 11 announced: All illegal access operations will be denied in a future release") - void error() throws IOException { - SimpleException error = null; - try { - proxy.error(); - } catch (SimpleException e) { - error = e; - } - assertNotNull(error); - assertEquals("foo", error.getMessage()); - } - @Test void undeclaredError() throws Exception { this.throwUndeclaredError = true; diff --git a/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java b/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java index 3ff7dd3c02b..98111a55ce8 100644 --- a/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java +++ b/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java @@ -49,11 +49,9 @@ import org.apache.avro.test.Kind; import org.apache.avro.compiler.specific.SpecificCompiler.OutputFile; -import org.junit.Rule; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.io.TempDir; -import org.junit.rules.TestName; public class TestSpecificCompiler { diff --git a/lang/java/ipc/src/test/java/org/apache/avro/io/Perf.java b/lang/java/ipc/src/test/java/org/apache/avro/io/Perf.java index cb01dd7fed8..9111a7fdf07 100644 --- a/lang/java/ipc/src/test/java/org/apache/avro/io/Perf.java +++ b/lang/java/ipc/src/test/java/org/apache/avro/io/Perf.java @@ -194,13 +194,13 @@ public static void main(String[] args) throws Exception { String a = args[i]; TestDescriptor t = ALL_TESTS.get(a); if (null != t) { - tests.add(t.test.newInstance()); + tests.add(t.test.getDeclaredConstructor().newInstance()); continue; } List lt = BATCHES.get(a); if (null != lt) { for (TestDescriptor td : lt) { - tests.add(td.test.newInstance()); + tests.add(td.test.getDeclaredConstructor().newInstance()); } continue; } @@ -257,7 +257,7 @@ public static void main(String[] args) throws Exception { if (tests.isEmpty()) { for (Map.Entry entry : ALL_TESTS.entrySet()) { TestDescriptor t = entry.getValue(); - Test test = t.test.newInstance(); + Test test = t.test.getDeclaredConstructor().newInstance(); tests.add(test); } } diff --git a/lang/java/java17-test/pom.xml b/lang/java/java17-test/pom.xml deleted file mode 100644 index d494dd16faa..00000000000 --- a/lang/java/java17-test/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - 4.0.0 - - - avro-parent - org.apache.avro - 1.13.0-SNAPSHOT - ../ - - - java17-test - Avro Java 17 Tests - Unit tests that require java 17 language support. - https://avro.apache.org/ - - - 17 - 17 - 17 - ${project.parent.parent.basedir} - - - - - ${project.groupId} - avro - ${project.version} - - - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - - \ No newline at end of file diff --git a/lang/java/mapred/pom.xml b/lang/java/mapred/pom.xml index 91982cfd110..faaa79340c5 100644 --- a/lang/java/mapred/pom.xml +++ b/lang/java/mapred/pom.xml @@ -45,8 +45,7 @@ org.apache.avro.mapred*;version="${project.version}", org.apache.avro.hadoop*;version="${project.version}", - 8 - 8 + 17 @@ -92,8 +91,6 @@ 1 false none - - -Djava.security.manager=allow diff --git a/lang/java/mapred/src/main/java/org/apache/avro/mapreduce/AvroOutputFormatBase.java b/lang/java/mapred/src/main/java/org/apache/avro/mapreduce/AvroOutputFormatBase.java index 5aa84b341d8..c1a8724b7c2 100644 --- a/lang/java/mapred/src/main/java/org/apache/avro/mapreduce/AvroOutputFormatBase.java +++ b/lang/java/mapred/src/main/java/org/apache/avro/mapreduce/AvroOutputFormatBase.java @@ -20,9 +20,7 @@ import java.io.IOException; import java.io.OutputStream; -import org.apache.hadoop.mapreduce.OutputCommitter; -import org.apache.avro.AvroRuntimeException; import org.apache.avro.file.CodecFactory; import org.apache.avro.file.DataFileConstants; import org.apache.avro.hadoop.file.HadoopCodecFactory; @@ -87,15 +85,7 @@ protected static CodecFactory getCompressionCodec(TaskAttemptContext context) { } private Path getWorkPathFromCommitter(TaskAttemptContext context) throws IOException { - // When Hadoop 2 support is dropped, this method removed to a simple cast - // See https://github.com/apache/avro/pull/1431/ - OutputCommitter committer = getOutputCommitter(context); - try { - return (Path) committer.getClass().getMethod("getWorkPath").invoke(committer); - } catch (ReflectiveOperationException e) { - throw new AvroRuntimeException( - "Committer: " + committer.getClass().getName() + " does not have method getWorkPath", e); - } + return ((org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter) getOutputCommitter(context)).getWorkPath(); } /** diff --git a/lang/java/maven-plugin/src/main/java/org/apache/avro/mojo/AbstractAvroMojo.java b/lang/java/maven-plugin/src/main/java/org/apache/avro/mojo/AbstractAvroMojo.java index 5615df36e3e..1de65a5e73e 100644 --- a/lang/java/maven-plugin/src/main/java/org/apache/avro/mojo/AbstractAvroMojo.java +++ b/lang/java/maven-plugin/src/main/java/org/apache/avro/mojo/AbstractAvroMojo.java @@ -149,8 +149,7 @@ public abstract class AbstractAvroMojo extends AbstractMojo { /** * The createOptionalGetters parameter enables generating the getOptional... - * methods that return an Optional of the requested type. This works ONLY on - * Java 8+ + * methods that return an Optional of the requested type. * * @parameter property="createOptionalGetters" */ @@ -158,7 +157,7 @@ public abstract class AbstractAvroMojo extends AbstractMojo { /** * The gettersReturnOptional parameter enables generating get... methods that - * return an Optional of the requested type. This works ONLY on Java 8+ + * return an Optional of the requested type. * * @parameter property="gettersReturnOptional" */ @@ -168,7 +167,7 @@ public abstract class AbstractAvroMojo extends AbstractMojo { * The optionalGettersForNullableFieldsOnly parameter works in conjunction with * gettersReturnOptional option. If it is set, Optional getters will be * generated only for fields that are nullable. If the field is mandatory, - * regular getter will be generated. This works ONLY on Java 8+. + * regular getter will be generated. * * @parameter property="optionalGettersForNullableFieldsOnly" */ diff --git a/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestInduceMojo.java b/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestInduceMojo.java index 6c93a382233..00f0ac854ef 100644 --- a/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestInduceMojo.java +++ b/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestInduceMojo.java @@ -22,7 +22,6 @@ import java.util.Arrays; import org.apache.avro.Protocol; -import org.apache.avro.Schema; import org.apache.avro.SchemaParser; import org.apache.avro.entities.Person; import org.apache.avro.protocols.Remote; diff --git a/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestSchemaMojo.java b/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestSchemaMojo.java index f54b9a40403..918251c10b0 100644 --- a/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestSchemaMojo.java +++ b/lang/java/maven-plugin/src/test/java/org/apache/avro/mojo/TestSchemaMojo.java @@ -20,7 +20,6 @@ import org.apache.maven.plugin.MojoExecutionException; import org.codehaus.plexus.util.FileUtils; import org.junit.Test; -import org.junit.jupiter.api.Assertions; import java.io.File; import java.nio.file.Files; diff --git a/lang/java/pom.xml b/lang/java/pom.xml index eece7212f8c..6222151cc24 100644 --- a/lang/java/pom.xml +++ b/lang/java/pom.xml @@ -91,7 +91,6 @@ integration-test perf interop-data-test - java17-test @@ -341,8 +340,7 @@ ${main.basedir}/lang/java/eclipse-java-formatter.xml 4.19 - - + Remove wildcard imports import\s+[^\*\s]+\*;(\r\n|\r|\n) @@ -501,13 +499,6 @@ - - - hadoop2 - - 2.10.1 - - - -Djava.security.manager=allow diff --git a/lang/java/trevni/pom.xml b/lang/java/trevni/pom.xml index 64fd16c10f6..1a1e8581acb 100644 --- a/lang/java/trevni/pom.xml +++ b/lang/java/trevni/pom.xml @@ -55,8 +55,6 @@ 1 false none - - -Djava.security.manager=allow diff --git a/pom.xml b/pom.xml index e17dc884d3b..8e8844024be 100644 --- a/pom.xml +++ b/pom.xml @@ -40,8 +40,7 @@ Java artifacts are copied to the final build destination with a custom profile. --> - 11 - 11 + 17 ${project.basedir} dist build/avro-doc-${project.version}/api @@ -182,32 +181,41 @@ maven-toolchains-plugin - Ensure ToolChain for JDK 11 is available + Ensure ToolChain for JDK 17 is available select-jdk-toolchain - [11,12) + [17,18) - Ensure ToolChain for JDK 17 is available + Ensure ToolChain for JDK 21 is available select-jdk-toolchain - [17,18) + [21,22) + + + + Ensure ToolChain for JDK 25 is available + + select-jdk-toolchain + + + [25,26) - Build using JDK 21 + Build using JDK 25 select-jdk-toolchain IfSame - [21,22) + [25,26) @@ -225,19 +233,11 @@ - 11 + 17 test provided - - - module-info -