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

io.lighty.codecs.util.JsonNodeConverter Maven / Gradle / Ivy

There is a newer version: 20.2.0
Show newest version
/*
 * Copyright (c) 2021 PANTHEON.tech s.r.o. All Rights Reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at https://www.eclipse.org/legal/epl-v10.html
 */
package io.lighty.codecs.util;

import com.google.common.base.Preconditions;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.lighty.codecs.util.exception.DeserializationException;
import io.lighty.codecs.util.exception.SerializationException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The implementation of {@link NodeConverter} which serializes and deserializes binding independent
 * representation into/from JSON representation.
 *
 * @see XmlNodeConverter
 */
public class JsonNodeConverter implements NodeConverter {
    private static final Logger LOG = LoggerFactory.getLogger(JsonNodeConverter.class);

    private final JSONCodecFactory jsonCodecFactory;

    /**
     * This constructor will create an instance of {@link JsonNodeConverter} with the given
     * {@link EffectiveModelContext}.
     *
     * 

* The effective model context will be used for proper RPC and Node resolution. * *

* The {@code JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02} will be used for JSON * serialization/deserialization of data. * * @param effectiveModelContext initial effective model context */ public JsonNodeConverter(final EffectiveModelContext effectiveModelContext) { this(effectiveModelContext, JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02); } /** * This constructor will create an instance of {@link JsonNodeConverter} with the given * {@link EffectiveModelContext} and customizable {@link JSONCodecFactorySupplier}. * *

* The effective model context will be used for proper RPC and Node resolution. * *

* The {@code JSONCodecFactorySupplier} instance will be used for JSON serialization/deserialization of data. * * @param effectiveModelContext initial effective model context * @param jsonCodecFactorySupplier JSON codec factory supplier */ public JsonNodeConverter(final EffectiveModelContext effectiveModelContext, final JSONCodecFactorySupplier jsonCodecFactorySupplier) { this.jsonCodecFactory = jsonCodecFactorySupplier.createLazy(effectiveModelContext); } /** * Serializes the given {@link NormalizedNode} into its {@link Writer} representation. * * @param inference {@link Inference} pointing to normalizedNode's parent * @param normalizedNode normalized node to serialize * @return {@link Writer} * @throws SerializationException if something goes wrong with serialization */ @Override public Writer serializeData(final Inference inference, final NormalizedNode normalizedNode) throws SerializationException { final Writer writer = new StringWriter(); final XMLNamespace initialNamespace = normalizedNode.name().getNodeType().getNamespace(); // nnStreamWriter closes underlying JsonWriter, we don't need too final JsonWriter jsonWriter = new JsonWriter(writer); // Exclusive nnWriter closes underlying NormalizedNodeStreamWriter, we don't need too final boolean useNested = normalizedNode instanceof MapEntryNode; final NormalizedNodeStreamWriter nnStreamWriter = useNested ? JSONNormalizedNodeStreamWriter.createNestedWriter( this.jsonCodecFactory, inference, initialNamespace, jsonWriter) : JSONNormalizedNodeStreamWriter.createExclusiveWriter( this.jsonCodecFactory, inference, initialNamespace, jsonWriter); try (NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter)) { nnWriter.write(normalizedNode); return writer; } catch (IOException e) { throw new SerializationException(e); } finally { if (useNested) { try { jsonWriter.close(); } catch (IOException e) { LOG.warn("Failed to close underlying JsonWriter", e); } } } } @Override public Writer serializeRpc(final Inference inference, final NormalizedNode normalizedNode) throws SerializationException { Preconditions.checkState(normalizedNode instanceof ContainerNode, "RPC input/output to serialize is expected to be a ContainerNode"); final XMLNamespace namespace = normalizedNode.name().getNodeType().getNamespace(); // Input/output final String localName = normalizedNode.name().getNodeType().getLocalName(); final Writer writer = new StringWriter(); // nnStreamWriter closes underlying JsonWriter, we don't need too final JsonWriter jsonWriter = new JsonWriter(writer); // nnWriter closes underlying NormalizedNodeStreamWriter, we don't need too final NormalizedNodeStreamWriter nnStreamWriter = JSONNormalizedNodeStreamWriter.createExclusiveWriter( this.jsonCodecFactory, inference, namespace, jsonWriter); try (NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter)) { jsonWriter.beginObject().name(localName); for (NormalizedNode child : ((ContainerNode) normalizedNode).body()) { normalizedNodeWriter.write(child); } jsonWriter.endObject(); return writer; } catch (IOException e) { throw new SerializationException(e); } } /** * Deserializes a given JSON input data into {@link NormalizedNode}. * * @param inference {@link Inference} pointing to a parent of the node to deserialize * @param inputData Reader containing input JSON data describing node to deserialize * @return deserialized {@link NormalizedNode} * @throws DeserializationException is thrown in case of an error during deserialization */ @Override public NormalizedNode deserialize(final Inference inference, final Reader inputData) throws DeserializationException { if (inference.statementPath().isEmpty()) { final DataContainerNodeBuilder resultBuilder = ImmutableNodes.newContainerBuilder().withNodeIdentifier(NodeIdentifier.create(SchemaContext.NAME)); parseToResult(ImmutableNormalizedNodeStreamWriter.from(resultBuilder), inputData, inference); return resultBuilder.build(); } else { final var result = new NormalizationResultHolder(); parseToResult(ImmutableNormalizedNodeStreamWriter.from(result), inputData, inference); return result.getResult().data(); } } private void parseToResult(final NormalizedNodeStreamWriter writer, final Reader data, final Inference inference) throws DeserializationException { try (JsonReader reader = new JsonReader(data); JsonParserStream jsonParser = JsonParserStream.create(writer, this.jsonCodecFactory, inference)) { jsonParser.parse(reader); } catch (IOException e) { throw new DeserializationException(e); } } @Override public EffectiveModelContext getModelContext() { return jsonCodecFactory.modelContext(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy