Skip to content

Java callers cannot specifically catch IOException from KmzParser.parse #1834

Open

Description

@blihio

Summary

KmzParser.parse(InputStream) can throw IOException for stream failures and KMZ safety-limit violations, but its Java signature does not declare it. A Java caller cannot compile a specific catch (IOException) when the try block contains only the parsing call.

Expected behavior

Provide a Java-callable entry point that declares the parser's I/O failures, while preserving the existing parse(InputStream) contract for current callers.

Observed behavior

The example below fails Java compilation:

error: exception IOException is never thrown in body of corresponding try statement

At runtime, the method can still propagate IOException. Catching Exception is a workaround, but requires a broader handler than the I/O failure being handled.

Environment details

  • Repository commit: b7b09e6c36e31a8fb4b309074de0b84f51eee3c9, module data.
  • Gradle 9.8.1, Kotlin 2.4.21, JDK 17.
  • Confirmed against the complete production module classes built with the repository's toolchain. No Android device is required for the Java compilation failure.

Steps to reproduce

  1. Build the data module and include its classes and dependencies on a Java consumer's compile classpath.
  2. Compile the class below. The catch (IOException) clause is rejected.
  3. Change the catch type to Exception and invoke the method with a stream whose read() throws IOException. The parsing call propagates that IOException to the handler.

Code example

import com.google.maps.android.data.parser.kml.KmzParser;
import java.io.IOException;
import java.io.InputStream;

public final class KmzConsumer {
    public static void load(InputStream input) {
        try {
            new KmzParser().parse(input);
        } catch (IOException failure) {
            System.err.println("Could not read KMZ: " + failure.getMessage());
        }
    }
}

Suggested approach

Keep parse(InputStream) unchanged and add a separate entry point, for example:

@Throws(IOException::class)
public fun parseChecked(inputStream: InputStream): Kml =
    parse(inputStream)

Java callers could opt into parseChecked() and catch IOException, without adding a checked exception to the existing method. The original parsing and stream-closing behavior would remain shared.

Alternatively, adding @Throws(IOException::class) directly to parse() would avoid introducing another method, but existing Java callers might need to catch or declare IOException when recompiling. The separate entry point would avoid that source-compatibility change.

Would this additional entry point fit the intended Java API, or would you prefer another way to expose these failures?

Validation

  • The original Java compilation failure and actual IOException propagation were reproduced against the real module classes.
  • An equivalent Java adapter declaring throws IOException was tested against those same classes. Existing direct callers and new adapter callers compile; stream-read failure handling and KMZ entry-limit rejection both pass.
  • The unmodified repository baseline passes :data:testDebugUnitTest :data:lintDebug: 187 tests, zero failures/errors/skips; lint reports eight warnings and no errors.
  • The proposed Kotlin entry point has not yet been added to the upstream source. The adapter checks and baseline results are not a patched-module test run.

Activity

  1. added
    priority: p0Highest priority. Critical issue. P0 implies highest priority.
    on Oct 27, 2026
  2. added
    priority: p3Desirable enhancement or fix. May not be included in next release.
    and removed
    priority: p0Highest priority. Critical issue. P0 implies highest priority.
    on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p3Desirable enhancement or fix. May not be included in next release.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions