diff options
23 files changed, 475 insertions, 491 deletions
diff --git a/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java index a46abce1dff..35a95ed3d89 100644 --- a/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java +++ b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java @@ -91,7 +91,6 @@ public class BundleTest { // From SimpleSearcher assertThat(importPackage, containsString("com.yahoo.prelude.hitfield")); - assertThat(importPackage, containsString("org.json")); // From SimpleSearcher2 assertThat(importPackage, containsString("com.yahoo.processing")); diff --git a/bundle-plugin-test/test-bundles/main/pom.xml b/bundle-plugin-test/test-bundles/main/pom.xml index c9c9ea270eb..190e1c9d90f 100644 --- a/bundle-plugin-test/test-bundles/main/pom.xml +++ b/bundle-plugin-test/test-bundles/main/pom.xml @@ -16,11 +16,6 @@ <packaging>container-plugin</packaging> <dependencies> <dependency> - <groupId>org.json</groupId> - <artifactId>json</artifactId> - <scope>provided</scope> - </dependency> - <dependency> <groupId>com.yahoo.vespa</groupId> <artifactId>jrt</artifactId> <version>${project.version}</version> diff --git a/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java index dddca3f4d59..ae9644aa010 100644 --- a/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java @@ -8,8 +8,6 @@ import com.yahoo.search.Searcher; import com.yahoo.search.result.Hit; import com.yahoo.search.searchchain.Execution; import com.yahoo.text.BooleanParser; -import org.json.JSONException; -import org.json.JSONObject; /** * A searcher adding a new hit. @@ -19,19 +17,13 @@ import org.json.JSONObject; public class SimpleSearcher extends Searcher { public Result search(Query query,Execution execution) { - try { BooleanParser.parseBoolean("true"); XMLString xmlString = new XMLString("<sampleXmlString/>"); Hit hit = new Hit("Hello world!"); - hit.setField("json", new JSONObject().put("price", 42).toString()); Result result = execution.search(query); result.hits().add(hit); return result; - - } catch (JSONException e) { - throw new RuntimeException(e); - } } } diff --git a/cloud-tenant-base-dependencies-enforcer/pom.xml b/cloud-tenant-base-dependencies-enforcer/pom.xml index a8655a82860..8bb7b75be89 100644 --- a/cloud-tenant-base-dependencies-enforcer/pom.xml +++ b/cloud-tenant-base-dependencies-enforcer/pom.xml @@ -34,7 +34,7 @@ <junit5.version>5.7.0</junit5.version> <junit5.platform.version>1.7.0</junit5.platform.version> <org.lz4.version>1.7.1</org.lz4.version> - <org.json.version>20090211</org.json.version> + <org.json.version>20090211</org.json.version><!-- TODO Vespa 8: remove as provided dependency --> <slf4j.version>1.7.5</slf4j.version> <tensorflow.version>1.12.0</tensorflow.version> <xml-apis.version>1.4.01</xml-apis.version> diff --git a/container-core/pom.xml b/container-core/pom.xml index 7c98b524c73..051b572b28f 100644 --- a/container-core/pom.xml +++ b/container-core/pom.xml @@ -42,6 +42,7 @@ <scope>test</scope> </dependency> <dependency> + <!-- TODO Vespa 8: stop providing org.json:json --> <groupId>org.json</groupId> <artifactId>json</artifactId> </dependency> diff --git a/container-core/src/main/java/org/json/package-info.java b/container-core/src/main/java/org/json/package-info.java index 44630ad235a..7ca9fe91e31 100644 --- a/container-core/src/main/java/org/json/package-info.java +++ b/container-core/src/main/java/org/json/package-info.java @@ -1,5 +1,5 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. @ExportPackage package org.json; - +// TODO Vespa 8: stop providing org.json import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-dependency-versions/pom.xml b/container-dependency-versions/pom.xml index 8691d9a7ffb..08d6e0103bf 100644 --- a/container-dependency-versions/pom.xml +++ b/container-dependency-versions/pom.xml @@ -313,7 +313,7 @@ <artifactId>javassist</artifactId> <version>${javassist.version}</version> </dependency> - <dependency> <!-- TODO Vespa 8: upgrade to newest version. Consider removing as provided dependency --> + <dependency> <!-- TODO Vespa 8: remove as provided dependency --> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>${org.json.version}</version> diff --git a/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java b/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java index 709441999d0..df7cacdc768 100644 --- a/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java +++ b/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java @@ -1,9 +1,13 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.usability; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.component.ComponentId; -import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.Container; import com.yahoo.container.jdisc.JdiscBindingsConfig; import com.yahoo.jdisc.handler.AbstractRequestHandler; @@ -15,16 +19,11 @@ import com.yahoo.jdisc.handler.ResponseDispatch; import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpRequest; import com.yahoo.jdisc.http.HttpRequest.Method; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; @@ -33,6 +32,8 @@ import java.util.Map; */ public class BindingsOverviewHandler extends AbstractRequestHandler { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private final JdiscBindingsConfig bindingsConfig; @Inject @@ -42,7 +43,7 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { @Override public ContentChannel handleRequest(com.yahoo.jdisc.Request request, ResponseHandler handler) { - JSONObject json; + JsonNode json; int statusToReturn; if (request instanceof HttpRequest && ((HttpRequest) request).getMethod() != Method.GET) { @@ -63,7 +64,9 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { }.connect(handler)); try { - writer.write(json.toString()); + writer.write(jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(json)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); } finally { writer.close(); } @@ -71,63 +74,58 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { return new IgnoredContent(); } - private JSONObject errorMessageInJson() { - JSONObject error = new JSONObject(); - try { - error.put("error", "This API, " - + this.getClass().getSimpleName() - + ", only supports HTTP GET." - + " You are probably looking for another API/path."); - } catch (org.json.JSONException e) { - // just ignore it - } + private static JsonNode errorMessageInJson() { + ObjectNode error = jsonMapper.createObjectNode(); + error.put("error", "This API, " + + BindingsOverviewHandler.class.getSimpleName() + + ", only supports HTTP GET." + + " You are probably looking for another API/path."); return error; } - static JSONArray renderRequestHandlers(JdiscBindingsConfig bindingsConfig, + static ArrayNode renderRequestHandlers(JdiscBindingsConfig bindingsConfig, Map<ComponentId, ? extends RequestHandler> handlersById) { - JSONArray ret = new JSONArray(); + ArrayNode ret = jsonMapper.createArrayNode(); for (Map.Entry<ComponentId, ? extends RequestHandler> handlerEntry : handlersById.entrySet()) { String id = handlerEntry.getKey().stringValue(); RequestHandler handler = handlerEntry.getValue(); - JSONObject handlerJson = renderComponent(handler, handlerEntry.getKey()); + ObjectNode handlerJson = renderComponent(handler, handlerEntry.getKey()); addBindings(bindingsConfig, id, handlerJson); - ret.put(handlerJson); + ret.add(handlerJson); } return ret; } - private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, JSONObject handlerJson) { + private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, ObjectNode handlerJson) { List<String> serverBindings = new ArrayList<>(); JdiscBindingsConfig.Handlers handlerConfig = bindingsConfig.handlers(id); if (handlerConfig != null) { serverBindings = handlerConfig.serverBindings(); } - putJson(handlerJson, "serverBindings", renderBindings(serverBindings)); + handlerJson.set("serverBindings", renderBindings(serverBindings)); } - private static JSONArray renderBindings(List<String> bindings) { - JSONArray array = new JSONArray(); + private static JsonNode renderBindings(List<String> bindings) { + ArrayNode array = jsonMapper.createArrayNode(); for (String binding : bindings) - array.put(binding); + array.add(binding); return array; } - private static JSONObject renderComponent(Object component, ComponentId id) { - JSONObject jc = new JSONObject(); - putJson(jc, "id", id.stringValue()); + private static ObjectNode renderComponent(Object component, ComponentId id) { + ObjectNode jc = jsonMapper.createObjectNode(); + jc.put("id", id.stringValue()); addBundleInfo(jc, component); return jc; } - private static void addBundleInfo(JSONObject jsonObject, Object component) { + private static void addBundleInfo(ObjectNode jsonObject, Object component) { BundleInfo bundleInfo = bundleInfo(component); - putJson(jsonObject, "class", bundleInfo.className); - putJson(jsonObject, "bundle", bundleInfo.bundleName); - + jsonObject.put("class", bundleInfo.className); + jsonObject.put("bundle", bundleInfo.bundleName); } private static BundleInfo bundleInfo(Object component) { @@ -143,15 +141,6 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { } } - private static void putJson(JSONObject json, String key, Object value) { - try { - json.put(key, value); - } catch (JSONException e) { - // The original JSONException lacks key-value info. - throw new RuntimeException("Trying to add invalid JSON object with key '" + key + "' and value '" + value + "' - " + e.getMessage(), e); - } - } - static final class BundleInfo { public final String className; @@ -172,10 +161,10 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { this.bindingsConfig = bindingsConfig; } - public JSONObject render() { - JSONObject root = new JSONObject(); + public JsonNode render() { + ObjectNode root = jsonMapper.createObjectNode(); - putJson(root, "handlers", + root.set("handlers", renderRequestHandlers(bindingsConfig, Container.get().getRequestHandlerRegistry().allComponentsById())); return root; diff --git a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java index 57c5e768cfb..943eef1e0bf 100644 --- a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java +++ b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java @@ -1,6 +1,11 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.observability; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; import com.yahoo.component.ComponentId; @@ -29,15 +34,11 @@ import com.yahoo.processing.execution.chain.ChainRegistry; import com.yahoo.processing.handler.ProcessingHandler; import com.yahoo.search.handler.SearchHandler; import com.yahoo.search.searchchain.SearchChainRegistry; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -51,11 +52,13 @@ import java.util.Map; */ public class ApplicationStatusHandler extends AbstractRequestHandler { - private final JSONObject applicationJson; - private final JSONArray clientsJson; - private final JSONArray serversJson; - private final JSONArray requestFiltersJson; - private final JSONArray responseFiltersJson; + private static final ObjectMapper jsonMapper = new ObjectMapper(); + + private final JsonNode applicationJson; + private final JsonNode clientsJson; + private final JsonNode serversJson; + private final JsonNode requestFiltersJson; + private final JsonNode responseFiltersJson; private final JdiscBindingsConfig bindingsConfig; @Inject @@ -78,7 +81,7 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { @Override public ContentChannel handleRequest(com.yahoo.jdisc.Request request, ResponseHandler handler) { - JSONObject json = new StatusResponse(applicationJson, clientsJson, serversJson, + JsonNode json = new StatusResponse(applicationJson, clientsJson, serversJson, requestFiltersJson, responseFiltersJson, bindingsConfig) .render(); @@ -91,62 +94,66 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } }.connect(handler)); - writer.write(json.toString()); + try { + writer.write(jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(json)); + } catch (JsonProcessingException e) { + throw new RuntimeException("Invalid JSON: " + e.getMessage(), e); + } writer.close(); return new IgnoredContent(); } - static JSONObject renderApplicationConfigs(ApplicationMetadataConfig metaConfig, + static JsonNode renderApplicationConfigs(ApplicationMetadataConfig metaConfig, ApplicationUserdataConfig userConfig) { - JSONObject vespa = new JSONObject(); - putJson(vespa, "version", Vtag.currentVersion); - - JSONObject meta = new JSONObject(); - putJson(meta, "name", metaConfig.name()); - putJson(meta, "user", metaConfig.user()); - putJson(meta, "path", metaConfig.path()); - putJson(meta, "generation", metaConfig.generation()); - putJson(meta, "timestamp", metaConfig.timestamp()); - putJson(meta, "date", new Date(metaConfig.timestamp()).toString()); - putJson(meta, "checksum", metaConfig.checksum()); - - JSONObject user = new JSONObject(); - putJson(user, "version", userConfig.version()); - - JSONObject application = new JSONObject(); - putJson(application, "vespa", vespa); - putJson(application, "meta", meta); - putJson(application, "user", user); + ObjectNode vespa = jsonMapper.createObjectNode(); + vespa.put("version", Vtag.currentVersion.toString()); + + ObjectNode meta = jsonMapper.createObjectNode(); + meta.put("name", metaConfig.name()); + meta.put("user", metaConfig.user()); + meta.put("path", metaConfig.path()); + meta.put("generation", metaConfig.generation()); + meta.put("timestamp", metaConfig.timestamp()); + meta.put("date", new Date(metaConfig.timestamp()).toString()); + meta.put("checksum", metaConfig.checksum()); + + ObjectNode user = jsonMapper.createObjectNode(); + user.put("version", userConfig.version()); + + ObjectNode application = jsonMapper.createObjectNode(); + application.set("vespa", vespa); + application.set("meta", meta); + application.set("user", user); return application; } - static JSONArray renderObjectComponents(Map<ComponentId, ?> componentsById) { - JSONArray ret = new JSONArray(); + static JsonNode renderObjectComponents(Map<ComponentId, ?> componentsById) { + ArrayNode ret = jsonMapper.createArrayNode(); for (Map.Entry<ComponentId, ?> componentEntry : componentsById.entrySet()) { - JSONObject jc = renderComponent(componentEntry.getValue(), componentEntry.getKey()); - ret.put(jc); + JsonNode jc = renderComponent(componentEntry.getValue(), componentEntry.getKey()); + ret.add(jc); } return ret; } - static JSONArray renderRequestHandlers(JdiscBindingsConfig bindingsConfig, + static JsonNode renderRequestHandlers(JdiscBindingsConfig bindingsConfig, Map<ComponentId, ? extends RequestHandler> handlersById) { - JSONArray ret = new JSONArray(); + ArrayNode ret = jsonMapper.createArrayNode(); for (Map.Entry<ComponentId, ? extends RequestHandler> handlerEntry : handlersById.entrySet()) { String id = handlerEntry.getKey().stringValue(); RequestHandler handler = handlerEntry.getValue(); - JSONObject handlerJson = renderComponent(handler, handlerEntry.getKey()); + ObjectNode handlerJson = renderComponent(handler, handlerEntry.getKey()); addBindings(bindingsConfig, id, handlerJson); - ret.put(handlerJson); + ret.add(handlerJson); } return ret; } - private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, JSONObject handlerJson) { + private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, ObjectNode handlerJson) { List<String> serverBindings = new ArrayList<>(); List<String> clientBindings = new ArrayList<>(); @@ -155,40 +162,40 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { serverBindings = handlerConfig.serverBindings(); clientBindings = handlerConfig.clientBindings(); } - putJson(handlerJson, "serverBindings", renderBindings(serverBindings)); - putJson(handlerJson, "clientBindings", renderBindings(clientBindings)); + handlerJson.set("serverBindings", renderBindings(serverBindings)); + handlerJson.set("clientBindings", renderBindings(clientBindings)); } - private static JSONArray renderBindings(List<String> bindings) { - JSONArray ret = new JSONArray(); + private static JsonNode renderBindings(List<String> bindings) { + ArrayNode ret = jsonMapper.createArrayNode(); for (String binding : bindings) - ret.put(binding); + ret.add(binding); return ret; } - private static JSONArray renderAbstractComponents(List<? extends AbstractComponent> components) { - JSONArray ret = new JSONArray(); + private static JsonNode renderAbstractComponents(List<? extends AbstractComponent> components) { + ArrayNode ret = jsonMapper.createArrayNode(); for (AbstractComponent c : components) { - JSONObject jc = renderComponent(c, c.getId()); - ret.put(jc); + JsonNode jc = renderComponent(c, c.getId()); + ret.add(jc); } return ret; } - private static JSONObject renderComponent(Object component, ComponentId id) { - JSONObject jc = new JSONObject(); - putJson(jc, "id", id.stringValue()); + private static ObjectNode renderComponent(Object component, ComponentId id) { + ObjectNode jc = jsonMapper.createObjectNode(); + jc.put("id", id.stringValue()); addBundleInfo(jc, component); return jc; } - private static void addBundleInfo(JSONObject jsonObject, Object component) { + private static void addBundleInfo(ObjectNode jsonObject, Object component) { BundleInfo bundleInfo = bundleInfo(component); - putJson(jsonObject, "class", bundleInfo.className); - putJson(jsonObject, "bundle", bundleInfo.bundleName); + jsonObject.put("class", bundleInfo.className); + jsonObject.put("bundle", bundleInfo.bundleName); } @@ -205,15 +212,6 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } } - private static void putJson(JSONObject json, String key, Object value) { - try { - json.put(key, value); - } catch (JSONException e) { - // The original JSONException lacks key-value info. - throw new RuntimeException("Trying to add invalid JSON object with key '" + key + "' and value '" + value + "' - " + e.getMessage(), e); - } - } - static final class BundleInfo { public final String className; public final String bundleName; @@ -224,18 +222,18 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } static final class StatusResponse { - private final JSONObject applicationJson; - private final JSONArray clientsJson; - private final JSONArray serversJson; - private final JSONArray requestFiltersJson; - private final JSONArray responseFiltersJson; + private final JsonNode applicationJson; + private final JsonNode clientsJson; + private final JsonNode serversJson; + private final JsonNode requestFiltersJson; + private final JsonNode responseFiltersJson; private final JdiscBindingsConfig bindingsConfig; - StatusResponse(JSONObject applicationJson, - JSONArray clientsJson, - JSONArray serversJson, - JSONArray requestFiltersJson, - JSONArray responseFiltersJson, + StatusResponse(JsonNode applicationJson, + JsonNode clientsJson, + JsonNode serversJson, + JsonNode requestFiltersJson, + JsonNode responseFiltersJson, JdiscBindingsConfig bindingsConfig) { this.applicationJson = applicationJson; this.clientsJson = clientsJson; @@ -245,52 +243,52 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { this.bindingsConfig = bindingsConfig; } - public JSONObject render() { - JSONObject root = new JSONObject(); + public JsonNode render() { + ObjectNode root = jsonMapper.createObjectNode(); - putJson(root, "application", applicationJson); - putJson(root, "abstractComponents", + root.set("application", applicationJson); + root.set("abstractComponents", renderAbstractComponents(Container.get().getComponentRegistry().allComponents())); - putJson(root, "handlers", + root.set("handlers", renderRequestHandlers(bindingsConfig, Container.get().getRequestHandlerRegistry().allComponentsById())); - putJson(root, "clients", clientsJson); - putJson(root, "servers", serversJson); - putJson(root, "httpRequestFilters", requestFiltersJson); - putJson(root, "httpResponseFilters", responseFiltersJson); + root.set("clients", clientsJson); + root.set("servers", serversJson); + root.set("httpRequestFilters", requestFiltersJson); + root.set("httpResponseFilters", responseFiltersJson); - putJson(root, "searchChains", renderSearchChains(Container.get())); - putJson(root, "docprocChains", renderDocprocChains(Container.get())); - putJson(root, "processingChains", renderProcessingChains(Container.get())); + root.set("searchChains", renderSearchChains(Container.get())); + root.set("docprocChains", renderDocprocChains(Container.get())); + root.set("processingChains", renderProcessingChains(Container.get())); return root; } - private static JSONObject renderSearchChains(Container container) { + private static JsonNode renderSearchChains(Container container) { for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof SearchHandler) { SearchChainRegistry scReg = ((SearchHandler) h).getSearchChainRegistry(); return renderChains(scReg); } } - return new JSONObject(); + return jsonMapper.createObjectNode(); } - private static JSONObject renderDocprocChains(Container container) { - JSONObject ret = new JSONObject(); + private static JsonNode renderDocprocChains(Container container) { + ObjectNode ret = jsonMapper.createObjectNode(); for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof DocumentProcessingHandler) { ComponentRegistry<DocprocService> registry = ((DocumentProcessingHandler) h).getDocprocServiceRegistry(); for (DocprocService service : registry.allComponents()) { - putJson(ret, service.getId().stringValue(), renderCalls(service.getCallStack().iterator())); + ret.set(service.getId().stringValue(), renderCalls(service.getCallStack().iterator())); } } } return ret; } - private static JSONObject renderProcessingChains(Container container) { - JSONObject ret = new JSONObject(); + private static JsonNode renderProcessingChains(Container container) { + JsonNode ret = jsonMapper.createObjectNode(); for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof ProcessingHandler) { ChainRegistry<Processor> registry = ((ProcessingHandler) h).getChainRegistry(); @@ -301,20 +299,20 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } // Note the generic param here! The key to make this work is '? extends Chain', but why? - static JSONObject renderChains(ComponentRegistry<? extends Chain<?>> chains) { - JSONObject ret = new JSONObject(); + static JsonNode renderChains(ComponentRegistry<? extends Chain<?>> chains) { + ObjectNode ret = jsonMapper.createObjectNode(); for (Chain<?> chain : chains.allComponents()) { - putJson(ret, chain.getId().stringValue(), renderAbstractComponents(chain.components())); + ret.set(chain.getId().stringValue(), renderAbstractComponents(chain.components())); } return ret; } - private static JSONArray renderCalls(Iterator<Call> components) { - JSONArray ret = new JSONArray(); + private static JsonNode renderCalls(Iterator<Call> components) { + ArrayNode ret = jsonMapper.createArrayNode(); while (components.hasNext()) { Call c = components.next(); - JSONObject jc = renderComponent(c.getDocumentProcessor(), c.getDocumentProcessor().getId()); - ret.put(jc); + JsonNode jc = renderComponent(c.getDocumentProcessor(), c.getDocumentProcessor().getId()); + ret.add(jc); } return ret; } diff --git a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java index 9ddcc7a7e69..3132f3744c9 100644 --- a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java +++ b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java @@ -1,8 +1,10 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.query.gui; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; - import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; @@ -11,6 +13,7 @@ import com.yahoo.prelude.IndexModel; import com.yahoo.prelude.querytransform.RecallSearcher; import com.yahoo.restapi.Path; import com.yahoo.search.Query; +import com.yahoo.search.config.IndexInfoConfig; import com.yahoo.search.query.Model; import com.yahoo.search.query.Presentation; import com.yahoo.search.query.Ranking; @@ -19,19 +22,12 @@ import com.yahoo.search.query.ranking.MatchPhase; import com.yahoo.search.query.restapi.ErrorResponse; import com.yahoo.search.yql.MinimalQueryInserter; import com.yahoo.vespa.config.search.RankProfilesConfig; -import com.yahoo.search.config.IndexInfoConfig; import com.yahoo.yolean.Exceptions; -import org.json.JSONException; -import org.json.JSONObject; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; import java.util.logging.Level; @@ -42,6 +38,8 @@ import java.util.logging.Level; */ public class GUIHandler extends LoggingRequestHandler { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private final IndexModel indexModel; private final RankProfilesConfig rankProfilesConfig; @@ -112,7 +110,7 @@ public class GUIHandler extends LoggingRequestHandler { InputStream is; if (this.path.equals("config.json")){ String json = "{}"; - try { json = getGUIConfig(); } catch (JSONException e) { /*Something happened while parsing JSON */ } + try { json = getGUIConfig(); } catch (IOException e) { /*Something happened while parsing JSON */ } is = new ByteArrayInputStream(json.getBytes()); } else{ is = GUIHandler.class.getClassLoader().getResourceAsStream("gui/"+this.path); @@ -160,50 +158,50 @@ public class GUIHandler extends LoggingRequestHandler { return "text/html"; } - private String getGUIConfig() throws JSONException { - JSONObject json = new JSONObject(); - json.put("ranking_properties", Arrays.asList("propertyname")); - json.put("ranking_features", Arrays.asList("featurename")); + private String getGUIConfig() throws IOException { + ObjectNode json = jsonMapper.createObjectNode(); + json.set("ranking_properties", jsonMapper.createArrayNode().add("propertyname")); + json.set("ranking_features", jsonMapper.createArrayNode().add("featurename")); - List<String> sources = new ArrayList<>(); + ArrayNode sources = jsonMapper.createArrayNode(); try { - sources = new ArrayList<>(indexModel.getMasterClusters().keySet()); + indexModel.getMasterClusters().keySet().forEach(sources::add); } catch (NullPointerException ex){ /* clusters are not set */ } - json.put("model_sources", sources); + json.set("model_sources", sources); - List<String> rankProfiles = new ArrayList<>(); + ArrayNode rankProfiles = jsonMapper.createArrayNode(); try { rankProfilesConfig.rankprofile().forEach(rankProfile -> rankProfiles.add(rankProfile.name())); } catch (NullPointerException ex){ /* rankprofiles are not set*/ } - json.put("ranking_profile", rankProfiles); + json.set("ranking_profile", rankProfiles); // Creating map from parent to children for GUI: parameter --> child-parameters - HashMap<String, List<String>> childMap = new HashMap<>(); - childMap.put(Model.MODEL, Arrays.asList(Model.DEFAULT_INDEX, Model.ENCODING, Model.LANGUAGE, Model.QUERY_STRING, Model.RESTRICT, Model.SEARCH_PATH, Model.SOURCES, Model.TYPE)); - childMap.put(Ranking.RANKING, Arrays.asList(Ranking.LOCATION, Ranking.FEATURES, Ranking.LIST_FEATURES, Ranking.PROFILE, Ranking.PROPERTIES, Ranking.SORTING, Ranking.FRESHNESS, Ranking.QUERYCACHE, Ranking.MATCH_PHASE)); - childMap.put(Ranking.RANKING +"."+ Ranking.MATCH_PHASE, Arrays.asList(MatchPhase.MAX_HITS, MatchPhase.ATTRIBUTE, MatchPhase.ASCENDING, Ranking.DIVERSITY)); - childMap.put(Ranking.RANKING +"."+ Ranking.MATCH_PHASE +"."+Ranking.DIVERSITY, Arrays.asList(Diversity.ATTRIBUTE, Diversity.MINGROUPS)); - childMap.put(Presentation.PRESENTATION, Arrays.asList(Presentation.BOLDING, Presentation.FORMAT, Presentation.SUMMARY, "template", Presentation.TIMING )); - childMap.put("trace", Arrays.asList("timestamps")); - childMap.put("tracelevel", Arrays.asList("rules")); - childMap.put("metrics", Arrays.asList("ignore")); - childMap.put("collapse", Arrays.asList("summary")); - childMap.put("pos", Arrays.asList("ll", "radius", "bb", "attribute")); - childMap.put("streaming", Arrays.asList("userid", "groupname", "selection", "priority", "maxbucketspervisitor")); - childMap.put("rules", Arrays.asList("off", "rulebase")); - json.put("childMap", childMap); - - List<String> levelZeroParameters = Arrays.asList(MinimalQueryInserter.YQL.toString(), Query.HITS.toString(), Query.OFFSET.toString(), - "queryProfile", Query.NO_CACHE.toString(), Query.GROUPING_SESSION_CACHE.toString(), - Query.SEARCH_CHAIN.toString(), Query.TIMEOUT.toString(), "trace", "tracelevel", - Query.TRACE_LEVEL.toString(), Query.EXPLAIN_LEVEL.toString(), "explainlevel", Model.MODEL, Ranking.RANKING, "collapse", "collapsesize","collapsefield", - Presentation.PRESENTATION, "pos", "streaming", "rules", RecallSearcher.recallName.toString(), "user", - "metrics", ""); - json.put("levelZeroParameters", levelZeroParameters); - - return json.toString(); + ObjectNode childMap = jsonMapper.createObjectNode(); + childMap.set(Model.MODEL, jsonMapper.createArrayNode().add(Model.DEFAULT_INDEX).add(Model.ENCODING).add(Model.LANGUAGE).add(Model.QUERY_STRING).add(Model.RESTRICT).add(Model.SEARCH_PATH).add(Model.SOURCES).add(Model.TYPE)); + childMap.set(Ranking.RANKING, jsonMapper.createArrayNode().add(Ranking.LOCATION).add(Ranking.FEATURES).add(Ranking.LIST_FEATURES).add(Ranking.PROFILE).add(Ranking.PROPERTIES).add(Ranking.SORTING).add(Ranking.FRESHNESS).add(Ranking.QUERYCACHE).add(Ranking.MATCH_PHASE)); + childMap.set(Ranking.RANKING +"."+ Ranking.MATCH_PHASE, jsonMapper.createArrayNode().add(MatchPhase.MAX_HITS).add(MatchPhase.ATTRIBUTE).add(MatchPhase.ASCENDING).add(Ranking.DIVERSITY)); + childMap.set(Ranking.RANKING +"."+ Ranking.MATCH_PHASE +"."+Ranking.DIVERSITY, jsonMapper.createArrayNode().add(Diversity.ATTRIBUTE).add(Diversity.MINGROUPS)); + childMap.set(Presentation.PRESENTATION, jsonMapper.createArrayNode().add(Presentation.BOLDING).add(Presentation.FORMAT).add(Presentation.SUMMARY).add("template").add(Presentation.TIMING )); + childMap.set("trace", jsonMapper.createArrayNode().add("timestamps")); + childMap.set("tracelevel", jsonMapper.createArrayNode().add("rules")); + childMap.set("metrics", jsonMapper.createArrayNode().add("ignore")); + childMap.set("collapse", jsonMapper.createArrayNode().add("summary")); + childMap.set("pos", jsonMapper.createArrayNode().add("ll").add("radius").add("bb").add("attribute")); + childMap.set("streaming", jsonMapper.createArrayNode().add("userid").add("groupname").add("selection").add("priority").add("maxbucketspervisitor")); + childMap.set("rules", jsonMapper.createArrayNode().add("off").add("rulebase")); + json.set("childMap", childMap); + + ArrayNode levelZeroParameters = jsonMapper.createArrayNode().add(MinimalQueryInserter.YQL.toString()).add(Query.HITS.toString()).add(Query.OFFSET.toString()) + .add("queryProfile").add(Query.NO_CACHE.toString()).add(Query.GROUPING_SESSION_CACHE.toString()) + .add(Query.SEARCH_CHAIN.toString()).add(Query.TIMEOUT.toString()).add("trace").add("tracelevel") + .add(Query.TRACE_LEVEL.toString()).add(Query.EXPLAIN_LEVEL.toString()).add("explainlevel").add(Model.MODEL).add(Ranking.RANKING).add("collapse").add("collapsesize").add("collapsefield") + .add(Presentation.PRESENTATION).add("pos").add("streaming").add("rules").add(RecallSearcher.recallName.toString()).add("user") + .add("metrics").add(""); + json.set("levelZeroParameters", levelZeroParameters); + + return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json); } } }
\ No newline at end of file diff --git a/container-search/pom.xml b/container-search/pom.xml index 074f5827122..014b7dda14f 100644 --- a/container-search/pom.xml +++ b/container-search/pom.xml @@ -150,6 +150,11 @@ <version>${project.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java index 209bfd08e6b..55438aa35ba 100644 --- a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java +++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java @@ -21,6 +21,7 @@ import java.util.Iterator; * * @author Steinar Knutsen */ +// TODO Vespa 8: remove methods leaking org.json types (replace with Slime equivalent?) public class JSONString implements Inspectable { private Inspector value; @@ -436,6 +437,8 @@ public class JSONString implements Inspectable { return content; } + /** @deprecated Use {@link #getContent()} instead and parse content yourself */ + @Deprecated(forRemoval = true, since = "7") public Object getParsedJSON() { initContent(); if (parsedJSON == null) { @@ -444,6 +447,7 @@ public class JSONString implements Inspectable { return parsedJSON; } + @Deprecated(forRemoval = true, since = "7") public void setParsedJSON(Object parsedJSON) { this.parsedJSON = parsedJSON; } diff --git a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java index 31f8194b3b7..c4f850307ae 100644 --- a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java +++ b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java @@ -45,8 +45,6 @@ import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.NanNumber; import com.yahoo.tensor.Tensor; -import org.json.JSONArray; -import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; @@ -671,14 +669,6 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } else if (field instanceof FieldValue) { // the null below is the field which has already been written ((FieldValue) field).serialize(null, new JsonWriter(generator)); - } else if (field instanceof JSONArray || field instanceof JSONObject) { - // org.json returns null if the object would not result in syntactically correct JSON - String s = field.toString(); - if (s == null) { - generator.writeNull(); - } else { - generator.writeRawValue(s); - } } else { generator.writeString(field.toString()); } diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java index d1399cabc75..49df321e581 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java @@ -4,16 +4,21 @@ package com.yahoo.prelude.fastsearch; import com.google.common.collect.ImmutableSet; import com.yahoo.config.subscription.ConfigGetter; import com.yahoo.data.access.slime.SlimeAdapter; +import com.yahoo.prelude.hitfield.JSONString; import com.yahoo.prelude.hitfield.RawData; import com.yahoo.prelude.hitfield.XMLString; -import com.yahoo.prelude.hitfield.JSONString; import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; -import com.yahoo.search.result.NanNumber; import com.yahoo.search.result.StructuredData; +import com.yahoo.slime.BinaryFormat; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Slime; +import com.yahoo.tensor.Tensor; +import com.yahoo.tensor.serialization.TypedBinaryFormat; +import org.junit.Test; + import java.nio.ByteBuffer; import java.nio.ByteOrder; - import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Iterator; @@ -21,14 +26,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import com.yahoo.slime.BinaryFormat; -import com.yahoo.slime.Cursor; -import com.yahoo.slime.Inspector; -import com.yahoo.slime.Slime; -import com.yahoo.tensor.Tensor; -import com.yahoo.tensor.serialization.TypedBinaryFormat; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -102,7 +99,7 @@ public class SlimeSummaryTestCase { if (hit.getField("jsonstring_field") instanceof JSONString) { JSONString jstr = (JSONString) hit.getField("jsonstring_field"); assertEquals("{\"foo\":1,\"bar\":2}", jstr.getContent()); - assertNotNull(jstr.getParsedJSON()); + assertNotNull(getParsedJSON(jstr)); com.yahoo.data.access.Inspector value = jstr.inspect(); assertEquals(1L, value.field("foo").asLong()); @@ -126,6 +123,8 @@ public class SlimeSummaryTestCase { assertEquals(tensor2, featureData.getTensor("tensor2_feature")); } + @SuppressWarnings("removal") private static Object getParsedJSON(JSONString jstr) { return jstr.getParsedJSON(); } + @Test public void testFieldAccessAPI() { DocsumDefinitionSet partialDocsum1 = createDocsumDefinitionSet(partial_summary1_cf); diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java index 3cca053d0e5..80e629ca4cb 100644 --- a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java @@ -1,10 +1,13 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.handler.test; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.container.Container; import com.yahoo.container.core.config.testutil.HandlersConfigurerTestWrapper; import com.yahoo.container.jdisc.HttpRequest; - import com.yahoo.container.jdisc.RequestHandlerTestDriver; import com.yahoo.container.protect.Error; import com.yahoo.io.IOUtils; @@ -13,8 +16,8 @@ import com.yahoo.search.handler.SearchHandler; import com.yahoo.search.searchchain.config.test.SearchChainConfigurerTestCase; import com.yahoo.slime.Inspector; import com.yahoo.slime.SlimeUtils; -import org.json.JSONArray; -import org.json.JSONObject; +import com.yahoo.test.json.JsonTestHelper; +import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -23,13 +26,19 @@ import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; -import java.util.Map; +import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.Map; import static com.yahoo.jdisc.http.HttpRequest.Method.GET; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * Tests submitting the query as JSON. @@ -38,6 +47,8 @@ import static org.junit.Assert.*; */ public class JSONSearchHandlerTestCase { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final String testDir = "src/test/java/com/yahoo/search/handler/test/config"; private static final String myHostnameHeader = "my-hostname-header"; private static final String selfHostname = HostName.getLocalhost(); @@ -97,8 +108,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testFailing() throws Exception { - JSONObject json = new JSONObject(); + public void testFailing() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "test"); json.put("searchChain", "classLoadingError"); assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NoClassDefFoundError")); @@ -106,16 +117,16 @@ public class JSONSearchHandlerTestCase { @Test - public synchronized void testPluginError() throws Exception { - JSONObject json = new JSONObject(); + public synchronized void testPluginError() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "test"); json.put("searchChain", "exceptionInPlugin"); assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NullPointerException")); } @Test - public synchronized void testWorkingReconfiguration() throws Exception { - JSONObject json = new JSONObject(); + public synchronized void testWorkingReconfiguration() throws IOException { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); assertJsonResult(json, driver); @@ -135,7 +146,7 @@ public class JSONSearchHandlerTestCase { } @Test - public void testInvalidYqlQuery() throws Exception { + public void testInvalidYqlQuery() throws IOException { IOUtils.copyDirectory(new File(testDir, "config_yql"), new File(tempDir), 1); generateComponentsConfigForActive(); configurer.reloadConfig(); @@ -143,7 +154,7 @@ public class JSONSearchHandlerTestCase { SearchHandler newSearchHandler = fetchSearchHandler(configurer); assertTrue("Do I have a new instance of the search handler?", searchHandler != newSearchHandler); try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(newSearchHandler)) { - JSONObject json = new JSONObject(); + ObjectNode json = jsonMapper.createObjectNode(); json.put("yql", "select * from foo where bar > 1453501295"); RequestHandlerTestDriver.MockResponseHandler responseHandler = newDriver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); responseHandler.readAll(); @@ -153,14 +164,14 @@ public class JSONSearchHandlerTestCase { // Query handling takes a different code path when a query profile is active, so we test both paths. @Test - public void testInvalidQueryParamWithQueryProfile() throws Exception { + public void testInvalidQueryParamWithQueryProfile() throws IOException { try (RequestHandlerTestDriver newDriver = driverWithConfig("config_invalid_param")) { testInvalidQueryParam(newDriver); } } - private void testInvalidQueryParam(final RequestHandlerTestDriver testDriver) throws Exception { - JSONObject json = new JSONObject(); + private void testInvalidQueryParam(final RequestHandlerTestDriver testDriver) { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "status_code:0"); json.put("hits", 20); json.put("offset", -20); @@ -173,16 +184,16 @@ public class JSONSearchHandlerTestCase { } @Test - public void testNormalResultJsonAliasRendering() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultJsonAliasRendering() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("format", "json"); json.put("query", "abc"); assertJsonResult(json, driver); } @Test - public void testNullQuery() throws Exception { - JSONObject json = new JSONObject(); + public void testNullQuery() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("format", "xml"); assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + @@ -195,8 +206,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testWebServiceStatus() throws Exception { - JSONObject json = new JSONObject(); + public void testWebServiceStatus() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "web_service_status_code"); RequestHandlerTestDriver.MockResponseHandler responseHandler = driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); @@ -206,39 +217,39 @@ public class JSONSearchHandlerTestCase { } @Test - public void testNormalResultImplicitDefaultRendering() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultImplicitDefaultRendering() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); assertJsonResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRendering() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultExplicitDefaultRendering() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); json.put("format", "default"); assertJsonResult(json, driver); } @Test - public void testNormalResultXmlAliasRendering() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultXmlAliasRendering() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); json.put("format", "xml"); assertXmlResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRenderingFullRendererName1() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultExplicitDefaultRenderingFullRendererName1() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); json.put("format", "XmlRenderer"); assertXmlResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRenderingFullRendererName2() throws Exception { - JSONObject json = new JSONObject(); + public void testNormalResultExplicitDefaultRenderingFullRendererName2() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); json.put("format", "JsonRenderer"); assertJsonResult(json, driver); @@ -253,7 +264,7 @@ public class JSONSearchHandlerTestCase { " </hit>\n" + "</result>\n"; - private void assertXmlResult(JSONObject json, RequestHandlerTestDriver driver) { + private void assertXmlResult(JsonNode json, RequestHandlerTestDriver driver) { assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), xmlResult); } @@ -263,7 +274,7 @@ public class JSONSearchHandlerTestCase { + "{\"id\":\"testHit\",\"relevance\":1.0,\"fields\":{\"uri\":\"testHit\"}}" + "]}}"; - private void assertJsonResult(JSONObject json, RequestHandlerTestDriver driver) { + private void assertJsonResult(JsonNode json, RequestHandlerTestDriver driver) { assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), jsonResult); } @@ -288,7 +299,7 @@ public class JSONSearchHandlerTestCase { } - private RequestHandlerTestDriver driverWithConfig(String configDirectory) throws Exception { + private RequestHandlerTestDriver driverWithConfig(String configDirectory) throws IOException { IOUtils.copyDirectory(new File(testDir, configDirectory), new File(tempDir), 1); generateComponentsConfigForActive(); configurer.reloadConfig(); @@ -299,44 +310,44 @@ public class JSONSearchHandlerTestCase { } @Test - public void testSelectParameters() throws Exception { - JSONObject json = new JSONObject(); + public void testSelectParameters() throws IOException { + ObjectNode json = jsonMapper.createObjectNode(); - JSONObject select = new JSONObject(); + ObjectNode select = jsonMapper.createObjectNode(); - JSONObject where = new JSONObject(); + ObjectNode where = jsonMapper.createObjectNode(); where.put("where", "where"); - JSONObject grouping = new JSONObject(); + ObjectNode grouping = jsonMapper.createObjectNode(); grouping.put("grouping", "grouping"); - select.put("where", where); - select.put("grouping", grouping); + select.set("where", where); + select.set("grouping", grouping); - json.put("select", select); + json.set("select", select); - Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes("utf-8")).get(); + Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes(StandardCharsets.UTF_8)).get(); Map<String, String> map = new HashMap<>(); searchHandler.createRequestMapping(inspector, map, ""); - JSONObject processedWhere = new JSONObject(map.get("select.where")); - assertEquals(where.toString(), processedWhere.toString()); + JsonNode processedWhere = jsonMapper.readTree(map.get("select.where")); + JsonTestHelper.assertJsonEquals(where.toString(), processedWhere.toString()); - JSONObject processedGrouping = new JSONObject(map.get("select.grouping")); - assertEquals(grouping.toString(), processedGrouping.toString()); + JsonNode processedGrouping = jsonMapper.readTree(map.get("select.grouping")); + JsonTestHelper.assertJsonEquals(grouping.toString(), processedGrouping.toString()); } @Test - public void testJsonQueryWithSelectWhere() throws Exception { - JSONObject root = new JSONObject(); - JSONObject select = new JSONObject(); - JSONObject where = new JSONObject(); - JSONArray term = new JSONArray(); - term.put("default"); - term.put("bad"); - where.put("contains", term); - select.put("where", where); - root.put("select", select); + public void testJsonQueryWithSelectWhere() { + ObjectNode root = jsonMapper.createObjectNode(); + ObjectNode select = jsonMapper.createObjectNode(); + ObjectNode where = jsonMapper.createObjectNode(); + ArrayNode term = jsonMapper.createArrayNode(); + term.add("default"); + term.add("bad"); + where.set("contains", term); + select.set("where", where); + root.set("select", select); // Run query String result = driver.sendRequest(uri + "searchChain=echoingQuery", com.yahoo.jdisc.http.HttpRequest.Method.POST, root.toString(), JSON_CONTENT_TYPE).readAll(); @@ -393,8 +404,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testJsonQueryWithYQL() throws Exception { - JSONObject root = new JSONObject(); + public void testJsonQueryWithYQL() { + ObjectNode root = jsonMapper.createObjectNode(); root.put("yql", "select * from sources * where default contains 'bad';"); // Run query @@ -404,10 +415,10 @@ public class JSONSearchHandlerTestCase { } @Test - public void testRequestMapping() throws Exception { - JSONObject json = new JSONObject(); + public void testRequestMapping() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("yql", "select * from sources * where sddocname contains \"blog_post\" limit 0 | all(group(date) max(3) order(-count())each(output(count())));"); - json.put("hits", 10.0); + json.put("hits", 10); json.put("offset", 5); json.put("queryProfile", "foo"); json.put("nocache", false); @@ -417,7 +428,7 @@ public class JSONSearchHandlerTestCase { json.put("select", "_all"); - JSONObject model = new JSONObject(); + ObjectNode model = jsonMapper.createObjectNode(); model.put("defaultIndex", 1); model.put("encoding", "json"); model.put("filter", "default"); @@ -427,9 +438,9 @@ public class JSONSearchHandlerTestCase { model.put("searchPath", "node1"); model.put("sources", "source1,source2"); model.put("type", "yql"); - json.put("model", model); + json.set("model", model); - JSONObject ranking = new JSONObject(); + ObjectNode ranking = jsonMapper.createObjectNode(); ranking.put("location", "123789.89123N;128123W"); ranking.put("features", "none"); ranking.put("listFeatures", false); @@ -439,61 +450,61 @@ public class JSONSearchHandlerTestCase { ranking.put("freshness", "0.05"); ranking.put("queryCache", false); - JSONObject matchPhase = new JSONObject(); + ObjectNode matchPhase = jsonMapper.createObjectNode(); matchPhase.put("maxHits", "100"); matchPhase.put("attribute", "title"); matchPhase.put("ascending", true); - JSONObject diversity = new JSONObject(); + ObjectNode diversity = jsonMapper.createObjectNode(); diversity.put("attribute", "title"); diversity.put("minGroups", 1); - matchPhase.put("diversity", diversity); - ranking.put("matchPhase", matchPhase); - json.put("ranking", ranking); + matchPhase.set("diversity", diversity); + ranking.set("matchPhase", matchPhase); + json.set("ranking", ranking); - JSONObject presentation = new JSONObject(); + ObjectNode presentation = jsonMapper.createObjectNode(); presentation.put("bolding", true); presentation.put("format", "json"); presentation.put("summary", "none"); presentation.put("template", "json"); presentation.put("timing", false); - json.put("presentation", presentation); + json.set("presentation", presentation); - JSONObject collapse = new JSONObject(); + ObjectNode collapse = jsonMapper.createObjectNode(); collapse.put("field", "none"); collapse.put("size", 2); collapse.put("summary", "default"); - json.put("collapse", collapse); + json.set("collapse", collapse); - JSONObject trace = new JSONObject(); + ObjectNode trace = jsonMapper.createObjectNode(); trace.put("level", 1); trace.put("timestamps", false); trace.put("rules", "none"); - json.put("trace", trace); + json.set("trace", trace); - JSONObject pos = new JSONObject(); + ObjectNode pos = jsonMapper.createObjectNode(); pos.put("ll", "1263123N;1231.9W"); pos.put("radius", "71234m"); pos.put("bb", "1237123W;123218N"); pos.put("attribute", "default"); - json.put("pos", pos); + json.set("pos", pos); - JSONObject streaming = new JSONObject(); + ObjectNode streaming = jsonMapper.createObjectNode(); streaming.put("userid", 123); streaming.put("groupname", "abc"); streaming.put("selection", "none"); streaming.put("priority", 10); streaming.put("maxbucketspervisitor", 5); - json.put("streaming", streaming); + json.set("streaming", streaming); - JSONObject rules = new JSONObject(); + ObjectNode rules = jsonMapper.createObjectNode(); rules.put("off", false); rules.put("rulebase", "default"); - json.put("rules", rules); + json.set("rules", rules); - JSONObject metrics = new JSONObject(); + ObjectNode metrics = jsonMapper.createObjectNode(); metrics.put("ignore", "_all"); - json.put("metrics", metrics); + json.set("metrics", metrics); json.put("recall", "none"); json.put("user", 123); @@ -501,7 +512,7 @@ public class JSONSearchHandlerTestCase { json.put("hitcountestimate", true); // Create mapping - Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes("utf-8")).get(); + Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes(StandardCharsets.UTF_8)).get(); Map<String, String> map = new HashMap<>(); searchHandler.createRequestMapping(inspector, map, ""); @@ -518,12 +529,12 @@ public class JSONSearchHandlerTestCase { // Get mapping Map<String, String> propertyMap = request.propertyMap(); - assertEquals("Should have same mapping for properties", map, propertyMap); + Assertions.assertThat(propertyMap).isEqualTo(map); } @Test - public void testContentTypeParsing() throws Exception { - JSONObject json = new JSONObject(); + public void testContentTypeParsing() { + ObjectNode json = jsonMapper.createObjectNode(); json.put("query", "abc"); assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), "Application/JSON; charset=utf-8"), jsonResult); } diff --git a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java index c4d49c11f5e..48003f6586f 100644 --- a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java @@ -1,7 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.rendering; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; @@ -56,9 +55,6 @@ import com.yahoo.tensor.TensorType; import com.yahoo.tensor.serialization.TypedBinaryFormat; import com.yahoo.text.Utf8; import com.yahoo.yolean.trace.TraceNode; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.Before; import org.junit.Test; @@ -67,7 +63,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -83,6 +78,8 @@ import static org.junit.Assert.assertTrue; */ public class JsonRendererTestCase { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private JsonRenderer originalRenderer; private JsonRenderer renderer; @@ -959,7 +956,7 @@ public class JsonRendererTestCase { } @Test - public void testJsonObjects() throws InterruptedException, ExecutionException, IOException, JSONException { + public void testJsonObjects() throws InterruptedException, ExecutionException, IOException { String expected = "{" + " \"root\": {" + " \"children\": [" @@ -973,14 +970,6 @@ public class JsonRendererTestCase { + " }," + " \"json producer\": {" + " \"long in structured\": 7809531904" - + " }," - + " \"org.json array\": [" - + " true," - + " true," - + " false" - + " ]," - + " \"org.json object\": {" - + " \"forty-two\": 42" + " }" + " }," + " \"id\": \"json objects\"," @@ -996,26 +985,17 @@ public class JsonRendererTestCase { + "}"; Result r = newEmptyResult(); Hit h = new Hit("json objects"); - JSONObject o = new JSONObject(); - JSONArray a = new JSONArray(); - ObjectMapper mapper = new ObjectMapper(); - JsonNode j = mapper.createObjectNode(); + ObjectNode j = jsonMapper.createObjectNode(); JSONString s = new JSONString("{\"a\": \"b\"}"); Slime slime = new Slime(); Cursor c = slime.setObject(); c.setLong("long in structured", 7809531904L); SlimeAdapter slimeInit = new SlimeAdapter(slime.get()); StructuredData struct = new StructuredData(slimeInit); - ((ObjectNode) j).put("Nineteen-eighty-four", 1984); - o.put("forty-two", 42); - a.put(true); - a.put(true); - a.put(false); + j.put("Nineteen-eighty-four", 1984); h.setField("inspectable", s); h.setField("jackson", j); h.setField("json producer", struct); - h.setField("org.json array", a); - h.setField("org.json object", o); r.hits().add(h); String summary = render(r); assertEqualJson(expected, summary); @@ -1236,11 +1216,13 @@ public class JsonRendererTestCase { public void testThatTheJsonValidatorCanCatchErrors() { String json = "{" + " \"root\": {" - + " \"duplicate\": 1," - + " \"duplicate\": 2" + + " \"invalidvalue\": 1adsf," + " }" + "}"; - assertEquals("Duplicate key \"duplicate\"", validateJSON(json)); + assertEquals( + "Unexpected character ('a' (code 97)): was expecting comma to separate Object entries\n" + + " at [Source: { \"root\": { \"invalidvalue\": 1adsf, }}; line: 1, column: 41]", + validateJSON(json)); } @Test @@ -1316,9 +1298,9 @@ public class JsonRendererTestCase { private String validateJSON(String presumablyValidJson) { try { - new JSONObject(presumablyValidJson); + jsonMapper.readTree(presumablyValidJson); return ""; - } catch (JSONException e) { + } catch (IOException e) { return e.getMessage(); } } diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java index 3239a97a094..9bcd3addd92 100644 --- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java +++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java @@ -1,6 +1,9 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.select; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.prelude.query.AndItem; import com.yahoo.prelude.query.ExactStringItem; import com.yahoo.prelude.query.Item; @@ -17,19 +20,15 @@ import com.yahoo.prelude.query.WordItem; import com.yahoo.processing.IllegalInputException; import com.yahoo.search.Query; import com.yahoo.search.grouping.GroupingRequest; -import com.yahoo.search.grouping.request.AllOperation; import com.yahoo.search.query.QueryTree; import com.yahoo.search.query.Select; import com.yahoo.search.query.SelectParser; import com.yahoo.search.query.parser.Parsable; import com.yahoo.search.query.parser.ParserEnvironment; import com.yahoo.search.yql.VespaGroupingStep; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.Test; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; @@ -48,15 +47,18 @@ import static org.junit.Assert.fail; */ public class SelectTestCase { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private final SelectParser parser = new SelectParser(new ParserEnvironment()); //------------------------------------------------------------------- "where" tests @Test - public void test_contains() throws Exception { - JSONObject json = new JSONObject(); - List<String> contains = Arrays.asList("default", "foo"); - json.put("contains", contains); + public void test_contains() { + ObjectNode json = jsonMapper.createObjectNode(); + ArrayNode arrayNode = jsonMapper.createArrayNode(); + arrayNode.add("default").add("foo"); + json.set("contains", arrayNode); assertParse(json.toString(), "default:foo"); } @@ -77,21 +79,21 @@ public class SelectTestCase { @Test public void testOr() throws Exception { - JSONObject json_two_or = new JSONObject(); - JSONObject json_three_or = new JSONObject(); - List<String> contains1 = Arrays.asList("title", "madonna"); - List<String> contains2 = Arrays.asList("title", "saint"); - List<String> contains3 = Arrays.asList("title", "angel"); - - JSONObject contains_json1 = new JSONObject(); - JSONObject contains_json2 = new JSONObject(); - JSONObject contains_json3 = new JSONObject(); - contains_json1.put("contains", contains1); - contains_json2.put("contains", contains2); - contains_json3.put("contains", contains3); - - json_two_or.put("or", Arrays.asList(contains_json1, contains_json2)); - json_three_or.put("or", Arrays.asList(contains_json1, contains_json2, contains_json3)); + ObjectNode json_two_or = jsonMapper.createObjectNode(); + ObjectNode json_three_or = jsonMapper.createObjectNode(); + ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); + ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); + ArrayNode contains3 = jsonMapper.createArrayNode().add("title").add("angel"); + + ObjectNode contains_json1 = jsonMapper.createObjectNode(); + ObjectNode contains_json2 = jsonMapper.createObjectNode(); + ObjectNode contains_json3 = jsonMapper.createObjectNode(); + contains_json1.set("contains", contains1); + contains_json2.set("contains", contains2); + contains_json3.set("contains", contains3); + + json_two_or.set("or", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); + json_three_or.set("or", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2).add(contains_json3)); assertParse(json_two_or.toString(), "OR title:madonna title:saint"); assertParse(json_three_or.toString(), "OR title:madonna title:saint title:angel"); @@ -99,178 +101,178 @@ public class SelectTestCase { @Test public void testAnd() throws Exception{ - JSONObject json_two_and = new JSONObject(); - JSONObject json_three_and = new JSONObject(); - List<String> contains1 = Arrays.asList("title", "madonna"); - List<String> contains2 = Arrays.asList("title", "saint"); - List<String> contains3 = Arrays.asList("title", "angel"); - - JSONObject contains_json1 = new JSONObject(); - JSONObject contains_json2 = new JSONObject(); - JSONObject contains_json3 = new JSONObject(); - contains_json1.put("contains", contains1); - contains_json2.put("contains", contains2); - contains_json3.put("contains", contains3); - - json_two_and.put("and", Arrays.asList(contains_json1, contains_json2)); - json_three_and.put("and", Arrays.asList(contains_json1, contains_json2, contains_json3)); + ObjectNode json_two_and = jsonMapper.createObjectNode(); + ObjectNode json_three_and = jsonMapper.createObjectNode(); + ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); + ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); + ArrayNode contains3 = jsonMapper.createArrayNode().add("title").add("angel"); + + ObjectNode contains_json1 = jsonMapper.createObjectNode(); + ObjectNode contains_json2 = jsonMapper.createObjectNode(); + ObjectNode contains_json3 = jsonMapper.createObjectNode(); + contains_json1.set("contains", contains1); + contains_json2.set("contains", contains2); + contains_json3.set("contains", contains3); + + json_two_and.set("and", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); + json_three_and.set("and", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2).add(contains_json3)); assertParse(json_two_and.toString(), "AND title:madonna title:saint"); assertParse(json_three_and.toString(), "AND title:madonna title:saint title:angel"); } @Test - public void testAndNot() throws JSONException { - JSONObject json_and_not = new JSONObject(); - List<String> contains1 = Arrays.asList("title", "madonna"); - List<String> contains2 = Arrays.asList("title", "saint"); + public void testAndNot() { + ObjectNode json_and_not = jsonMapper.createObjectNode(); + ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); + ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); - JSONObject contains_json1 = new JSONObject(); - JSONObject contains_json2 = new JSONObject(); - contains_json1.put("contains", contains1); - contains_json2.put("contains", contains2); + ObjectNode contains_json1 = jsonMapper.createObjectNode(); + ObjectNode contains_json2 = jsonMapper.createObjectNode(); + contains_json1.set("contains", contains1); + contains_json2.set("contains", contains2); - json_and_not.put("and_not", Arrays.asList(contains_json1, contains_json2)); + json_and_not.set("and_not", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); assertParse(json_and_not.toString(), "+title:madonna -title:saint"); } @Test - public void testLessThan() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testLessThan() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("<", 500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:<500"); } @Test - public void testGreaterThan() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testGreaterThan() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put(">", 500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:>500"); } @Test - public void testLessThanOrEqual() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testLessThanOrEqual() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("<=", 500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:[;500]"); } @Test - public void testGreaterThanOrEqual() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testGreaterThanOrEqual() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put(">=", 500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:[500;]"); } @Test - public void testEquality() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testEquality() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("=", 500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:500"); } @Test - public void testNegativeLessThan() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testNegativeLessThan() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("<", -500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:<-500"); } @Test - public void testNegativeGreaterThan() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testNegativeGreaterThan() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put(">", -500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:>-500"); } @Test - public void testNegativeLessThanOrEqual() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testNegativeLessThanOrEqual() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("<=", -500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:[;-500]"); } @Test - public void testNegativeGreaterThanOrEqual() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testNegativeGreaterThanOrEqual() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put(">=", -500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:[-500;]"); } @Test - public void testNegativeEquality() throws JSONException { - JSONObject range_json = new JSONObject(); - JSONObject operators = new JSONObject(); + public void testNegativeEquality() { + ObjectNode range_json = jsonMapper.createObjectNode(); + ObjectNode operators = jsonMapper.createObjectNode(); operators.put("=", -500); - List<Object> range = Arrays.asList("price", operators); + ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); - range_json.put("range", range); + range_json.set("range", range); assertParse(range_json.toString(), "price:-500"); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java index c6d907ec7fc..ed88902e094 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java @@ -1,14 +1,19 @@ package com.yahoo.vespa.hosted.controller.api.application.v4.model; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; -import org.json.JSONException; -import org.json.JSONObject; public class ProtonMetrics { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final Logger logger = LogManager.getLogManager().getLogger(ProtonMetrics.class.getName()); public static final String DOCUMENTS_ACTIVE_COUNT = "documentsActiveCount"; @@ -45,19 +50,19 @@ public class ProtonMetrics { return this; } - public JSONObject toJson() { + public JsonNode toJson() { try { - JSONObject protonMetrics = new JSONObject(); + ObjectNode protonMetrics = jsonMapper.createObjectNode(); protonMetrics.put("clusterId", clusterId); - JSONObject jsonMetrics = new JSONObject(); + ObjectNode jsonMetrics = jsonMapper.createObjectNode(); for (Map.Entry<String, Double> entry : metrics.entrySet()) { jsonMetrics.put(entry.getKey(), entry.getValue()); } - protonMetrics.put("metrics", jsonMetrics); + protonMetrics.set("metrics", jsonMetrics); return protonMetrics; - } catch (JSONException e) { - logger.severe("Unable to convert Proton Metrics to JSON Object"); + } catch (Exception e) { + logger.log(Level.SEVERE, "Unable to convert Proton Metrics to JSON Object: " + e.getMessage(), e); } - return new JSONObject(); + return jsonMapper.createObjectNode(); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 5a1496bf507..431a694fcd8 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -2,6 +2,8 @@ package com.yahoo.vespa.hosted.controller.restapi.application; import ai.vespa.hosted.api.Signatures; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; @@ -100,9 +102,6 @@ import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import com.yahoo.vespa.serviceview.bindings.ApplicationView; import com.yahoo.yolean.Exceptions; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import javax.ws.rs.ForbiddenException; import javax.ws.rs.InternalServerErrorException; @@ -151,6 +150,8 @@ import static java.util.stream.Collectors.toUnmodifiableList; @SuppressWarnings("unused") // created by injection public class ApplicationApiHandler extends LoggingRequestHandler { + private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final String OPTIONAL_PREFIX = "/api"; private final Controller controller; @@ -789,15 +790,15 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private JsonResponse buildResponseFromProtonMetrics(List<ProtonMetrics> protonMetrics) { try { - var jsonObject = new JSONObject(); - var jsonArray = new JSONArray(); + var jsonObject = jsonMapper.createObjectNode(); + var jsonArray = jsonMapper.createArrayNode(); for (ProtonMetrics metrics : protonMetrics) { - jsonArray.put(metrics.toJson()); + jsonArray.add(metrics.toJson()); } - jsonObject.put("metrics", jsonArray); - return new JsonResponse(200, jsonObject.toString()); - } catch (JSONException e) { - log.severe("Unable to build JsonResponse with Proton data"); + jsonObject.set("metrics", jsonArray); + return new JsonResponse(200, jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject)); + } catch (JsonProcessingException e) { + log.log(Level.SEVERE, "Unable to build JsonResponse with Proton data: " + e.getMessage(), e); return new JsonResponse(500, ""); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java index bda5a708a94..2bf6eb39089 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java @@ -9,6 +9,7 @@ import com.yahoo.config.provision.ApplicationName; import com.yahoo.container.http.filter.FilterChainRepository; import com.yahoo.jdisc.http.filter.SecurityRequestFilter; import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; +import com.yahoo.test.json.JsonTestHelper; import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.hosted.controller.Controller; @@ -65,6 +66,10 @@ public class ContainerTester { .addRoleMember(action, identity); } + public void assertJsonResponse(Supplier<Request> request, File responseFile) { + assertResponse(request.get(), responseFile, 200, false, true); + } + public void assertResponse(Supplier<Request> request, File responseFile) { assertResponse(request.get(), responseFile); } @@ -82,6 +87,10 @@ public class ContainerTester { } public void assertResponse(Request request, File responseFile, int expectedStatusCode, boolean removeWhitespace) { + assertResponse(request, responseFile, expectedStatusCode, removeWhitespace, false); + } + + private void assertResponse(Request request, File responseFile, int expectedStatusCode, boolean removeWhitespace, boolean compareJson) { String expectedResponse = readTestFile(responseFile.toString()); expectedResponse = include(expectedResponse); if (removeWhitespace) expectedResponse = expectedResponse.replaceAll("(\"[^\"]*\")|\\s*", "$1"); // Remove whitespace @@ -106,7 +115,11 @@ public class ContainerTester { expectedResponsePattern, responseString); } } else { - assertEquals(responseFile.toString(), expectedResponse, responseString); + if (compareJson) { + JsonTestHelper.assertJsonEquals(expectedResponse, responseString); + } else { + assertEquals(responseFile.toString(), expectedResponse, responseString); + } } assertEquals("Status code", expectedStatusCode, response.getStatus()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index 434c83898ee..63ad8004473 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -514,7 +514,7 @@ public class ApplicationApiTest extends ControllerContainerTest { updateMetrics(); // GET metrics - tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/metrics", GET) + tester.assertJsonResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/metrics", GET) .userIdentity(USER_ID), new File("proton-metrics.json")); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java index 828e2856cae..c43abf276c5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.restapi.application; import com.yahoo.component.Version; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.test.json.JsonTestHelper; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; @@ -12,8 +13,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.TestReport; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -180,12 +179,10 @@ public class JobControllerApiHandlerHelperTest { "jobs-direct-deployment.json"); } - private void compare(HttpResponse response, String expected) throws JSONException, IOException { + private void compare(HttpResponse response, String expected) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); response.render(baos); - JSONObject actualJSON = new JSONObject(new String(baos.toByteArray())); - JSONObject expectedJSON = new JSONObject(expected); - assertEquals(expectedJSON.toString(), actualJSON.toString()); + JsonTestHelper.assertJsonEquals(expected, baos.toString()); } private void assertResponse(HttpResponse response, String fileName) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json index a7e5b3918d8..3fba9b3c91c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json @@ -1,23 +1,26 @@ { - "metrics": [{ - "clusterId": "content/doc/", - "metrics": { - "resourceMemoryUsageAverage": 0.103482, - "documentsReadyCount": 11430, - "documentDiskUsage": 44021, - "resourceDiskUsageAverage": 0.0168421, - "documentsTotalCount": 11430, - "documentsActiveCount": 11430 + "metrics": [ + { + "clusterId": "content/doc/", + "metrics": { + "resourceMemoryUsageAverage": 0.103482, + "documentsReadyCount": 11430.0, + "documentDiskUsage": 44021.0, + "resourceDiskUsageAverage": 0.0168421, + "documentsTotalCount": 11430.0, + "documentsActiveCount": 11430.0 + } + }, + { + "clusterId": "content/music/", + "metrics": { + "resourceMemoryUsageAverage": 0.00912, + "documentsReadyCount": 32000.0, + "documentDiskUsage": 90113.0, + "resourceDiskUsageAverage": 0.23912, + "documentsTotalCount": 32210.0, + "documentsActiveCount": 32210.0 + } } - }, { - "clusterId": "content/music/", - "metrics": { - "resourceMemoryUsageAverage": 0.00912, - "documentsReadyCount": 32000, - "documentDiskUsage": 90113, - "resourceDiskUsageAverage": 0.23912, - "documentsTotalCount": 32210, - "documentsActiveCount": 32210 - } - }] -}
\ No newline at end of file + ] +} |