Commit 42c77062 authored by Florian Schäfer's avatar Florian Schäfer

Add generic method to query the Wikidata Action API and JSON schema for...

Add generic method to query the Wikidata Action API and JSON schema for checking if an entity exists

This adds a dependency to the Jackson-databind library.
parent 4e8616d3
......@@ -24,6 +24,7 @@ repositories {
jcenter()
}
dependencies {
packIntoJar "com.fasterxml.jackson.core:jackson-databind:2.9.5"
errorprone "com.google.errorprone:error_prone_core:${versions.errorprone}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit}"
......@@ -31,6 +32,11 @@ dependencies {
implementation "com.github.spotbugs:spotbugs-annotations:${versions.spotbugs}"
testImplementation("org.openstreetmap.josm:josm-unittest:"){changing=true}
}
task copyToLib(type: Sync) {
from configurations.packIntoJar
into file("$projectDir/lib")
}
classes.dependsOn(copyToLib)
test {
useJUnitPlatform()
......
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api;
import java.net.URL;
import javax.annotation.Nonnull;
public class InvalidApiQueryException extends Exception {
public InvalidApiQueryException(@Nonnull final URL url) {
super("The API query to the following URL is invalid: " + url);
}
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api.wikidata_action;
import java.io.IOException;
import java.net.URL;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openstreetmap.josm.gui.bugreport.BugReportDialog;
import org.openstreetmap.josm.tools.HttpClient;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.bugreport.BugReport;
import org.wikipedia.api.InvalidApiQueryException;
public final class ApiQueryClient {
private static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();
static {
JSON_OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
private ApiQueryClient() {
// Private constructor to avoid instantiation
}
/**
* Queries the given URL and converts the received JSON to the given class using the Jackson library
* @param url the {@link URL} to query
* @param klass the class object of the desired type
* @param <T> the type to which the JSON is deserialized
* @return the deserialized object
* @throws IOException if any error occurs while executing the query, with a translated message that can be shown to the user.
*/
public static <T> T query(final URL url, final Class<T> klass) throws IOException {
final HttpClient.Response response;
try {
response = HttpClient.create(url)
.setAccept("application/json")
.setHeader("User-Agent", "JOSM-wikipedia (). Report issues at https://josm.openstreetmap.de/newticket?component=Plugin%20wikipedia&priority=major&keywords=api%20wikidata%20ActionAPI")
.connect();
} catch (IOException e) {
// i18n: {0} is the name of the exception, {1} is the message of the exception. Typical values would be: {0}="UnknownHostException" {1}="www.wikidata.org"
throw new IOException(I18n.tr("Could not connect to the Wikidata Action API, probably a network issue or the website is currently offline ({0}: {1})", e.getClass().getSimpleName(), e.getLocalizedMessage()), e);
}
if (response.getResponseCode() != 200) {
// i18n: {0} is the response code, {1} is the response message. Typical values would be: {0}=404 {1}="Not Found"
throw new IOException(I18n.tr("The Wikidata Action API responded with an unexpected response code: {0} {1}", response.getResponseCode(), response.getResponseMessage()));
}
final String errorHeader = response.getHeaderField("MediaWiki-API-Error");
if (errorHeader != null) {
Logging.error(I18n.tr("The Wikidata Action API reported a query failure for URL {0} ({1}). This is a programming error, please report to the Wikipedia plugin.", url, errorHeader));
BugReport report = new BugReport(BugReport.intercept(new InvalidApiQueryException(url)));
BugReportDialog dialog = new BugReportDialog(report);
dialog.setVisible(true);
throw new IOException(I18n.tr("The Wikidata Action API reported that the query was invalid! Please report as bug to the Wikipedia plugin!"));
}
try {
return JSON_OBJECT_MAPPER.readValue(response.getContent(), klass);
} catch (JsonMappingException | JsonParseException e) {
throw new IOException(I18n.tr("The JSON response from the Wikidata Action API can't be read!"), e);
} catch (IOException e) {
throw new IOException(I18n.tr("When reading the JSON response from the Wikidata Action API, an error occured! ({0}: {1})", e.getClass().getSimpleName(), e.getLocalizedMessage()), e);
}
}
}
......@@ -13,6 +13,10 @@ import org.wikipedia.tools.RegexUtil;
public class WikidataActionApiUrl {
private static final String BASE_URL = "https://www.wikidata.org/w/api.php";
private WikidataActionApiUrl() {
// Private constructor to avoid instantiation
}
@Nonnull
public static URL checkEntityExistsUrl(@Nonnull final Collection<String> qIds) {
if (qIds.size() < 1) {
......
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api.wikidata_action.json;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public final class CheckEntityExistsResult {
private final int success;
private final Map<String, Entity> entities;
@JsonCreator
public CheckEntityExistsResult(@JsonProperty("success") final int success, @JsonProperty("entities") final Map<String, Entity> entities) {
this.success = success;
this.entities = entities;
}
public int getSuccess() {
return success;
}
public Map<String, Entity> getEntities() {
return Collections.unmodifiableMap(entities);
}
public static final class Entity {
private final String id;
private final String type;
@JsonCreator
public Entity(@JsonProperty("id") final String id, @JsonProperty("type") final String type) {
this.id = id;
this.type = type;
}
public String getId() {
return id;
}
public String getType() {
return type;
}
}
}
\ No newline at end of file
{"entities":{"Q1":{"id":"Q1","type":"item"},"Q1234567":{"id":"Q1234567","missing":""}},"success":1}
\ No newline at end of file
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api.wikidata_action.json;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.wikipedia.api.wikidata_action.WikidataActionApiUrlTest;
public class CheckEntityExistsResultTest {
@Test
public void test() throws IOException {
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
final CheckEntityExistsResult enitityQueryResult = mapper.readValue(
CheckEntityExistsResultTest.class.getResourceAsStream("response-wbgetentities-checkExists-Q1_Q1234567.json"),
CheckEntityExistsResult.class
);
assertEquals(1, enitityQueryResult.getSuccess());
assertEquals(2, enitityQueryResult.getEntities().size());
assertEquals("Q1", enitityQueryResult.getEntities().get("Q1").getId());
assertEquals("item", enitityQueryResult.getEntities().get("Q1").getType());
assertEquals("Q1234567", enitityQueryResult.getEntities().get("Q1234567").getId());
assertNull(enitityQueryResult.getEntities().get("Q1234567").getType());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment