Ticket #22680: 22680.patch

File 22680.patch, 6.9 KB (added by taylor.smock, 3 years ago)
  • src/org/openstreetmap/josm/io/OsmJsonReader.java

    Subject: [PATCH] Fix #22680: Unexpected exception downloading from Overpass query
    ---
    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/src/org/openstreetmap/josm/io/OsmJsonReader.java b/src/org/openstreetmap/josm/io/OsmJsonReader.java
    a b  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    66import java.io.InputStream;
     7import java.net.SocketException;
    78import java.util.Collection;
    89import java.util.Map.Entry;
    910
    1011import javax.json.Json;
    1112import javax.json.JsonArray;
     13import javax.json.JsonException;
    1214import javax.json.JsonNumber;
    1315import javax.json.JsonObject;
    1416import javax.json.JsonString;
    1517import javax.json.JsonValue;
    1618import javax.json.stream.JsonParser;
    1719import javax.json.stream.JsonParser.Event;
     20import javax.json.stream.JsonParsingException;
    1821
    1922import org.openstreetmap.josm.data.osm.DataSet;
    2023import org.openstreetmap.josm.data.osm.PrimitiveData;
     
    178181
    179182    @Override
    180183    protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
    181         return doParseDataSet(source, progressMonitor, ir -> {
    182             setParser(Json.createParser(ir));
    183             parse();
    184         });
     184        try {
     185            return doParseDataSet(source, progressMonitor, ir -> {
     186                setParser(Json.createParser(ir));
     187                parse();
     188            });
     189        } catch (JsonParsingException exception) {
     190            throw new IllegalDataException(exception);
     191        } catch (JsonException exception) {
     192            if (exception.getCause() instanceof SocketException) {
     193                SocketException soe = (SocketException) exception.getCause();
     194                soe.addSuppressed(exception); // Add the caught exception as a suppressed exception
     195                throw new IllegalDataException(soe); // NOPMD -- PreserveStackTrace should be fixed with PMD 7
     196            }
     197            throw exception;
     198        }
    185199    }
    186200
    187201    /**
  • test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java b/test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java
    a b  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.io;
    33
     4import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    45import static org.junit.jupiter.api.Assertions.assertEquals;
    56import static org.junit.jupiter.api.Assertions.assertFalse;
     7import static org.junit.jupiter.api.Assertions.assertThrows;
    68import static org.junit.jupiter.api.Assertions.assertTrue;
    79
    810import java.io.ByteArrayInputStream;
     11import java.io.IOException;
    912import java.io.InputStream;
     13import java.net.SocketException;
    1014import java.nio.charset.StandardCharsets;
    1115import java.time.Instant;
    1216import java.util.Iterator;
     17import java.util.concurrent.atomic.AtomicBoolean;
    1318
     19import javax.json.JsonException;
     20
     21import org.junit.jupiter.api.Test;
    1422import org.openstreetmap.josm.data.coor.LatLon;
    1523import org.openstreetmap.josm.data.osm.DataSet;
    1624import org.openstreetmap.josm.data.osm.Node;
     
    1927import org.openstreetmap.josm.data.osm.Way;
    2028import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    2129import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
    22 
    23 import org.junit.jupiter.api.Test;
     30import org.openstreetmap.josm.tools.ExceptionUtil;
    2431
    2532/**
    2633 * Unit tests of {@link OsmReader} class.
     
    246253                "  \"remark\": \"runtime error: Query ran out of memory in \\\"query\\\" at line 5.\"\n");
    247254        assertEquals("runtime error: Query ran out of memory in \"query\" at line 5.", ds.getRemark());
    248255    }
     256
     257
     258    /**
     259     * See #22680: Unexpected exception downloading from Overpass query
     260     * The JSON parser throws {@link RuntimeException}s, specifically
     261     * <ul>
     262     *     <li>{@link javax.json.JsonException}</li>
     263     *     <li>{@link javax.json.stream.JsonParsingException}, extends {@link javax.json.JsonException}</li>
     264     *     <li>{@link javax.json.stream.JsonGenerationException}, extends {@link javax.json.JsonException}
     265     *         (which we don't care about when we are <em>parsing</em> JSON)</li>
     266     * </ul>
     267     */
     268    @SuppressWarnings("resource")
     269    @Test
     270    void testException() {
     271        final ByteArrayInputStream bais =
     272                new ByteArrayInputStream("{\"type\", \"node\", \"id\": 1, \"lat\": 1.0, \"lon\": 2.0}".getBytes(StandardCharsets.UTF_8));
     273        final AtomicBoolean throwJson = new AtomicBoolean();
     274        final InputStream socketExceptionStream = new InputStream() {
     275            int read = 0; // Necessary, since otherwise the exception might not be wrapped in a Json exception
     276            @Override
     277            public int read() throws IOException {
     278                try {
     279                    if (read > 0 && !throwJson.get()) {
     280                        throw new SocketException("Read timed out");
     281                    } else if (read > 0 && throwJson.get()) {
     282                        throw new JsonException("Some random json exception");
     283                    }
     284                    return bais.read();
     285                } finally {
     286                    read++;
     287                }
     288            }
     289        };
     290        // Check that a SocketException is properly reported
     291        IllegalDataException ide = assertThrows(IllegalDataException.class,
     292                () -> OsmJsonReader.parseDataSet(socketExceptionStream, NullProgressMonitor.INSTANCE));
     293        assertEquals("java.net.SocketException: Read timed out", ExceptionUtil.explainException(ide));
     294        assertDoesNotThrow(socketExceptionStream::close);
     295        bais.reset();
     296        // Check that a generic exception is properly thrown -- we only want to handle known "good" cases specially
     297        throwJson.set(true);
     298        assertThrows(JsonException.class, () -> OsmJsonReader.parseDataSet(socketExceptionStream, NullProgressMonitor.INSTANCE));
     299        bais.reset();
     300        // Check that a generic parsing error is properly reported
     301        ide = assertThrows(IllegalDataException.class, () -> OsmJsonReader.parseDataSet(bais, NullProgressMonitor.INSTANCE));
     302        assertEquals("javax.json.stream.JsonParsingException: Invalid token=COMMA at (line no=1, column no=8, offset=7). " +
     303                "Expected tokens are: [COLON]", ExceptionUtil.explainException(ide));
     304        bais.reset();
     305        // Check that an unknown exception is thrown properly
     306    }
    249307}