All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.awssdk.protocols.jsoncore.JsonNodeParser Maven / Gradle / Ivy

There is a newer version: 2.29.17
Show newest version
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package software.amazon.awssdk.protocols.jsoncore;

import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import software.amazon.awssdk.annotations.SdkProtectedApi;
import software.amazon.awssdk.protocols.jsoncore.internal.ArrayJsonNode;
import software.amazon.awssdk.protocols.jsoncore.internal.EmbeddedObjectJsonNode;
import software.amazon.awssdk.protocols.jsoncore.internal.ObjectJsonNode;
import software.amazon.awssdk.thirdparty.jackson.core.JsonFactory;
import software.amazon.awssdk.thirdparty.jackson.core.JsonParseException;
import software.amazon.awssdk.thirdparty.jackson.core.JsonParser;
import software.amazon.awssdk.thirdparty.jackson.core.JsonToken;
import software.amazon.awssdk.thirdparty.jackson.core.json.JsonReadFeature;

/**
 * Parses an JSON document into a simple DOM-like structure, {@link JsonNode}.
 *
 * 

This is created using {@link #create()} or {@link #builder()}. */ @SdkProtectedApi public final class JsonNodeParser { /** * The default {@link JsonFactory} used for {@link #create()} or if a factory is not configured via * {@link Builder#jsonFactory(JsonFactory)}. */ public static final JsonFactory DEFAULT_JSON_FACTORY = JsonFactory.builder() .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true) .build(); private final boolean removeErrorLocations; private final JsonFactory jsonFactory; private final JsonValueNodeFactory jsonValueNodeFactory; private JsonNodeParser(Builder builder) { this.removeErrorLocations = builder.removeErrorLocations; this.jsonFactory = builder.jsonFactory; this.jsonValueNodeFactory = builder.jsonValueNodeFactory; } /** * Create a parser using the default configuration. */ public static JsonNodeParser create() { return builder().build(); } /** * Create a parser using custom configuration. */ public static JsonNodeParser.Builder builder() { return new Builder(); } /** * Parse the provided {@link InputStream} into a {@link JsonNode}. */ public JsonNode parse(InputStream content) { return invokeSafely(() -> { try (JsonParser parser = jsonFactory.createParser(content) .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false)) { return parse(parser); } }); } /** * Parse the provided {@code byte[]} into a {@link JsonNode}. */ public JsonNode parse(byte[] content) { return invokeSafely(() -> { try (JsonParser parser = jsonFactory.createParser(content) .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false)) { return parse(parser); } }); } /** * Parse the provided {@link String} into a {@link JsonNode}. */ public JsonNode parse(String content) { return invokeSafely(() -> { try (JsonParser parser = jsonFactory.createParser(content) .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false)) { return parse(parser); } }); } private JsonNode parse(JsonParser parser) throws IOException { try { return parseToken(parser, parser.nextToken()); } catch (Exception e) { removeErrorLocationsIfRequired(e); throw e; } } private void removeErrorLocationsIfRequired(Throwable exception) { if (removeErrorLocations) { removeErrorLocations(exception); } } private void removeErrorLocations(Throwable exception) { if (exception == null) { return; } if (exception instanceof JsonParseException) { ((JsonParseException) exception).clearLocation(); } removeErrorLocations(exception.getCause()); } private JsonNode parseToken(JsonParser parser, JsonToken token) throws IOException { if (token == null) { return null; } switch (token) { case VALUE_STRING: case VALUE_FALSE: case VALUE_TRUE: case VALUE_NULL: case VALUE_NUMBER_FLOAT: case VALUE_NUMBER_INT: return jsonValueNodeFactory.node(parser, token); case START_OBJECT: return parseObject(parser); case START_ARRAY: return parseArray(parser); case VALUE_EMBEDDED_OBJECT: return new EmbeddedObjectJsonNode(parser.getEmbeddedObject()); default: throw new IllegalArgumentException("Unexpected JSON token - " + token); } } private JsonNode parseObject(JsonParser parser) throws IOException { JsonToken currentToken = parser.nextToken(); Map object = new LinkedHashMap<>(); while (currentToken != JsonToken.END_OBJECT) { String fieldName = parser.getText(); object.put(fieldName, parseToken(parser, parser.nextToken())); currentToken = parser.nextToken(); } return new ObjectJsonNode(object); } private JsonNode parseArray(JsonParser parser) throws IOException { JsonToken currentToken = parser.nextToken(); List array = new ArrayList<>(); while (currentToken != JsonToken.END_ARRAY) { array.add(parseToken(parser, currentToken)); currentToken = parser.nextToken(); } return new ArrayJsonNode(array); } /** * A builder for configuring and creating {@link JsonNodeParser}. Created via {@link #builder()}. */ public static final class Builder { private JsonFactory jsonFactory = DEFAULT_JSON_FACTORY; private JsonValueNodeFactory jsonValueNodeFactory = JsonValueNodeFactory.DEFAULT; private boolean removeErrorLocations = false; private Builder() { } /** * Whether error locations should be removed if parsing fails. This prevents the content of the JSON from appearing in * error messages. This is useful when the content of the JSON may be sensitive and not want to be logged. * *

By default, this is false. */ public Builder removeErrorLocations(boolean removeErrorLocations) { this.removeErrorLocations = removeErrorLocations; return this; } /** * The {@link JsonFactory} implementation to be used when parsing the input. This allows JSON extensions like CBOR or * Ion to be supported. * *

It's highly recommended us use a shared {@code JsonFactory} where possible, so they should be stored statically: * http://wiki.fasterxml.com/JacksonBestPracticesPerformance * *

By default, this is {@link #DEFAULT_JSON_FACTORY}. */ public Builder jsonFactory(JsonFactory jsonFactory) { this.jsonFactory = jsonFactory; return this; } /** * Factory to create JsonNode out of JSON tokens. This allows JSON variants, such as CBOR, to produce actual values * instead of having to parse them out of strings. * *

By default, this is {@link JsonValueNodeFactory#DEFAULT}. */ public Builder jsonValueNodeFactory(JsonValueNodeFactory jsonValueNodeFactory) { this.jsonValueNodeFactory = jsonValueNodeFactory; return this; } /** * Build a {@link JsonNodeParser} based on the current configuration of this builder. */ public JsonNodeParser build() { return new JsonNodeParser(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy