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

io.micronaut.json.JsonMapper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017-2021 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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 io.micronaut.json;

import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.io.buffer.ByteBuffer;
import io.micronaut.core.order.OrderUtil;
import io.micronaut.core.type.Argument;
import io.micronaut.json.tree.JsonNode;
import org.reactivestreams.Processor;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.function.Consumer;
import java.util.stream.Stream;

/**
 * Common abstraction for mapping json to data structures.
 *
 * @author Jonas Konrad
 * @since 3.1
 */
@Experimental
public interface JsonMapper {
    /**
     * Specialize this mapper for the given type. Read and write operations on the returned mapper
     * may only be called with that type.
     *
     * @param type The type to read or write
     * @return The specialized {@link JsonMapper}.
     */
    @NonNull
    default JsonMapper createSpecific(@NonNull Argument type) {
        return this;
    }

    /**
     * Transform a {@link JsonNode} to a value of the given type.
     *
     * @param tree The input json data.
     * @param type The type to deserialize.
     * @param  Type variable of the return type.
     * @return The deserialized value.
     * @throws IOException IOException
     */
     T readValueFromTree(@NonNull JsonNode tree, @NonNull Argument type) throws IOException;

    /**
     * Transform a {@link JsonNode} to a value of the given type.
     *
     * @param tree The input json data.
     * @param type The type to deserialize.
     * @param  Type variable of the return type.
     * @return The deserialized value.
     * @throws IOException IOException
     */
    default  T readValueFromTree(@NonNull JsonNode tree, @NonNull Class type) throws IOException {
        return readValueFromTree(tree, Argument.of(type));
    }

    /**
     * Parse and map json from the given stream.
     *
     * @param inputStream The input data.
     * @param type The type to deserialize to.
     * @param  Type variable of the return type.
     * @return The deserialized object.
     * @throws IOException IOException
     */
     T readValue(@NonNull InputStream inputStream, @NonNull Argument type) throws IOException;

    /**
     * Read a value from the given input stream for the given type.
     *
     * @param inputStream The input stream
     * @param type The type
     * @param  The generic type
     * @return The value or {@code null} if it decodes to null
     * @throws IOException If an unrecoverable error occurs
     */
    default @Nullable  T readValue(@NonNull InputStream inputStream, @NonNull Class type) throws IOException {
        Objects.requireNonNull(type, "Type cannot be null");
        return readValue(inputStream, Argument.of(type));
    }

    /**
     * Parse and map json from the given byte array.
     *
     * @param byteArray The input data.
     * @param type The type to deserialize to.
     * @param  Type variable of the return type.
     * @return The deserialized object.
     * @throws IOException IOException
     */
     T readValue(byte @NonNull [] byteArray, @NonNull Argument type) throws IOException;

    /**
     * Parse and map json from the given byte buffer.
     *
     * @param byteBuffer The input data.
     * @param type The type to deserialize to.
     * @param  Type variable of the return type.
     * @return The deserialized object.
     * @throws IOException IOException
     */
    default  T readValue(@NonNull ByteBuffer byteBuffer, @NonNull Argument type) throws IOException {
        return readValue(byteBuffer.toByteArray(), type);
    }

    /**
     * Parse and map json from the given string.
     *
     * @param string The input data.
     * @param type The type to deserialize to.
     * @param  Type variable of the return type.
     * @return The deserialized object.
     * @throws IOException IOException
     */
    default  T readValue(@NonNull String string, @NonNull Argument type) throws IOException {
        return readValue(string.getBytes(StandardCharsets.UTF_8), type);
    }

    /**
     * Read a value from the byte array for the given type.
     *
     * @param byteArray The byte array
     * @param type The type
     * @param  The generic type
     * @return The value or {@code null} if it decodes to null
     * @throws IOException If an unrecoverable error occurs
     * @since 4.0.0
     */
    default @Nullable  T readValue(byte @NonNull [] byteArray, @NonNull Class type) throws IOException {
        Objects.requireNonNull(type, "Type cannot be null");
        return readValue(byteArray, Argument.of(type));
    }

    /**
     * Read a value from the given string for the given type.
     *
     * @param string The string
     * @param type The type
     * @param  The generic type
     * @return The value or {@code null} if it decodes to null
     * @throws IOException If an unrecoverable error occurs
     */
    default @Nullable  T readValue(@NonNull String string, @NonNull Class type) throws IOException {
        Objects.requireNonNull(type, "Type cannot be null");
        return readValue(string, Argument.of(type));
    }

    /**
     * Create a reactive {@link Processor} that accepts json bytes and parses them as {@link JsonNode}s.
     *
     * @param onSubscribe An additional function to invoke with this processor when the returned processor is subscribed to.
     * @param streamArray Whether to return a top-level json array as a stream of elements rather than a single array.
     * @return The reactive processor.
     */
    @NonNull
    @Deprecated
    default Processor createReactiveParser(@NonNull Consumer> onSubscribe, boolean streamArray) {
        throw new UnsupportedOperationException("Reactive parser not supported");
    }

    /**
     * Transform an object value to a json tree.
     *
     * @param value The object value to transform.
     * @return The json representation.
     * @throws IOException If there are any mapping exceptions (e.g. illegal values).
     */
    @NonNull
    JsonNode writeValueToTree(@Nullable Object value) throws IOException;

    /**
     * Transform an object value to a json tree.
     *
     * @param type The object type
     * @param value The object value to transform.
     * @param  The type variable of the type.
     * @return The json representation.
     * @throws IOException If there are any mapping exceptions (e.g. illegal values).
     */
    @NonNull
     JsonNode writeValueToTree(@NonNull Argument type, @Nullable T value) throws IOException;

    /**
     * Write an object as json.
     *
     * @param outputStream The stream to write to.
     * @param object The object to serialize.
     * @throws IOException IOException
     */
    void writeValue(@NonNull OutputStream outputStream, @Nullable Object object) throws IOException;

    /**
     * Write an object as json.
     *
     * @param outputStream The stream to write to.
     * @param type The object type
     * @param object The object to serialize.
     * @param  The generic type
     * @throws IOException IOException
     */
     void writeValue(@NonNull OutputStream outputStream, @NonNull Argument type, @Nullable T object) throws IOException;

    /**
     * Write an object as json.
     *
     * @param object The object to serialize.
     * @return The serialized encoded json.
     * @throws IOException IOException
     */
    byte[] writeValueAsBytes(@Nullable Object object) throws IOException;

    /**
     * Write an object as json.
     *
     * @param type The object type
     * @param object The object to serialize.
     * @param  The generic type
     * @return The serialized encoded json.
     * @throws IOException IOException
     */
     byte[] writeValueAsBytes(@NonNull Argument type, @Nullable T object) throws IOException;

    /**
     * Write the given value as a string.
     *
     * @param object The object
     * @return The string
     * @throws IOException If an unrecoverable error occurs
     * @since 4.0.0
     */
    default @NonNull String writeValueAsString(@NonNull Object object) throws IOException {
        Objects.requireNonNull(object, "Object cannot be null");
        return new String(writeValueAsBytes(object), StandardCharsets.UTF_8);
    }

    /**
     * Write the given value as a string.
     *
     * @param type The type, never {@code null}
     * @param object The object
     * @param  The generic type
     * @return The string
     * @throws IOException If an unrecoverable error occurs
     * @since 4.0.0
     */
    default @NonNull  String writeValueAsString(@NonNull Argument type, @Nullable T object) throws IOException {
        return writeValueAsString(type, object, StandardCharsets.UTF_8);
    }

    /**
     * Write the given value as a string.
     *
     * @param type The type, never {@code null}
     * @param object The object
     * @param charset The charset, never {@code null}
     * @param  The generic type
     * @return The string
     * @throws IOException If an unrecoverable error occurs
     * @since 4.0.0
     */
    default @NonNull  String writeValueAsString(@NonNull Argument type, @Nullable T object, Charset charset) throws IOException {
        Objects.requireNonNull(charset, "Charset cannot be null");
        byte[] bytes = writeValueAsBytes(type, object);
        return new String(bytes, charset);
    }

    /**
     * Update an object from json data.
     *
     * @param value The object to update.
     * @param tree The json data to update from.
     * @throws IOException If there are any mapping exceptions (e.g. illegal values).
     * @throws UnsupportedOperationException If this operation is not supported.
     */
    @Experimental
    default void updateValueFromTree(Object value, @NonNull JsonNode tree) throws IOException {
        throw new UnsupportedOperationException();
    }

    /**
     * Create a copy of this mapper with the given json features as returned by {@link #detectFeatures}.
     *
     * @param features The json features to configure.
     * @return A new mapper.
     */
    @NonNull
    default JsonMapper cloneWithFeatures(@NonNull JsonFeatures features) {
        throw new UnsupportedOperationException();
    }

    /**
     * Detect {@link JsonFeatures} from the given annotation data.
     *
     * @param annotations The annotations to scan.
     * @return The json features for use in {@link #cloneWithFeatures}, or an empty optional if there were no feature
     * annotations detected (or feature annotations are not supported).
     */
    @NonNull
    default Optional detectFeatures(@NonNull AnnotationMetadata annotations) {
        return Optional.empty();
    }

    /**
     * Create a copy of this mapper with the given view class.
     *
     * @param viewClass The view class to use for serialization and deserialization.
     * @return A new mapper.
     * @throws UnsupportedOperationException If views are not supported by this mapper.
     */
    @NonNull
    default JsonMapper cloneWithViewClass(@NonNull Class viewClass) {
        throw new UnsupportedOperationException();
    }

    /**
     * @return The configured stream config.
     */
    @NonNull
    JsonStreamConfig getStreamConfig();

    /**
     * Resolves the default {@link JsonMapper}.
     *
     * @return The default {@link JsonMapper}
     * @throws IllegalStateException If no {@link JsonMapper} implementation exists on the classpath.
     * @since 4.0.0
     */
    static @NonNull JsonMapper createDefault() {
        return ServiceLoader.load(JsonMapperSupplier.class).stream()
            .flatMap(p -> {
                try {
                    JsonMapperSupplier supplier = p.get();
                    return Stream.ofNullable(supplier);
                } catch (Exception e) {
                    return Stream.empty();
                }
            })
            .sorted(OrderUtil.COMPARATOR)
            .flatMap(jsonMapperSupplier -> {
                try {
                    return Stream.of(jsonMapperSupplier.get());
                } catch (Exception e) {
                    return Stream.empty();
                }
            })
            .findFirst()
            .orElseThrow(() -> new IllegalStateException("No JsonMapper implementation found"));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy