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

net.dongliu.xhttp.json.JsonProcessor Maven / Gradle / Ivy

The newest version!
package net.dongliu.xhttp.json;

import net.dongliu.xhttp.*;
import net.dongliu.xhttp.body.AbstractBody;
import net.dongliu.xhttp.body.Body;

import java.io.*;
import java.lang.reflect.Type;
import java.net.http.HttpRequest;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;

/**
 * Json processor, used to decode/encode json values, blocking and non-blocking.
 *
 * @author Liu Dong
 */
public abstract class JsonProcessor {

    /**
     * Serialize value to json, and write to writer. The output stream is leaved unclosed.
     */
    protected abstract void marshal(Object value, OutputStream out, Charset charset) throws IOException;

    /**
     * Deserialize json from Reader, to specific type. The input stream is closed when finished or error occurred.
     *
     * @param charset the charset, cannot be null
     */
    protected abstract  T unmarshal(InputStream in, Charset charset, Type type) throws IOException;

    /**
     * Create a new json http body
     *
     * @param value the value of body, to be marshall by this processor
     * @param    the value type
     * @return json http body
     */
    public  Body jsonBody(T value) {
        return new JsonBody<>(value);
    }

    /**
     * Create a new json http body
     *
     * @param value the value of body, to be marshall by this processor
     * @param    the value type
     * @return json http body
     */
    public  Body jsonBody(T value, Charset charset) {
        return new JsonBody<>(value, charset);
    }

    /**
     * Return a ResponseHandler, which deserialize json with charset and type.
     */
    public  ResponseHandler responseHandler(Class type) {
        return responseHandler((Type) type);
    }

    /**
     * Return a ResponseHandler, which deserialize json with charset and type.
     */
    public  ResponseHandler responseHandler(TypeToken type) {
        return responseHandler(type.getType());
    }


    /**
     * Return a ResponseHandler, which deserialize json with charset and type.
     */
    private  ResponseHandler responseHandler(Type type) {
        return (statusCode, headers, body, charset) -> unmarshal(body, charset.get(), type);
    }

    /**
     * Return a AsyncResponseHandler, which deserialize json from ByteBuffers async, with charset and type.
     */
    public  AsyncResponseHandler asyncResponseHandler(TypeToken typeToken) {
        return asyncResponseHandler(typeToken.getType());
    }

    /**
     * Return a AsyncResponseHandler, which deserialize json from ByteBuffers async, with charset and type.
     */
    public  AsyncResponseHandler asyncResponseHandler(Class cls) {
        return asyncResponseHandler((Type) cls);
    }

    /**
     * Return a AsyncResponseHandler, which deserialize json from ByteBuffers async, with charset and type.
     * Default impl read all data of response body unblocking, and then unmarshal using blocking api.
     * Override this method if implementation can decode json with non-blocking API.
     */
    protected  AsyncResponseHandler asyncResponseHandler(Type type) {
        requireNonNull(type);
        return new JsonBodyHandler<>(type);
    }


    /**
     * Json http body
     *
     * @param  the value type
     */
    private class JsonBody extends AbstractBody implements Body {

        private JsonBody(T value) {
            this(value, UTF_8);
        }

        private JsonBody(T value, Charset charset) {
            super(value, ContentType.of(MimeType.JSON, requireNonNull(charset)));
        }

        @Override
        public HttpRequest.BodyPublisher asBodyPublisher() {
            return asPublisher(body(), contentType().charset().orElseThrow());
        }

        /**
         * Marshal value to json, for async http using. Default using block api to get all data once, and then publish.
         *
         * @param value   the value
         * @param charset the charset
         * @return http body publisher
         */
        HttpRequest.BodyPublisher asPublisher(Object value, Charset charset) {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                marshal(value, bos, charset);
                return HttpRequest.BodyPublishers.ofByteArray(bos.toByteArray());
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    }

    private class JsonBodyHandler implements AsyncResponseHandler {
        private Charset charset;
        private final Type type;
        private List buffers;

        private JsonBodyHandler(Type type) {
            this.type = type;
        }


        @Override
        public void onHeader(int statusCode, Headers headers, Supplier charset) {
            this.charset = charset.get();
            this.buffers = new ArrayList<>();
        }

        @Override
        public void onBodyChunk(ByteBuffer buffer) {
            this.buffers.add(buffer);
        }

        @Override
        public T onBodyEnd() throws Exception {
            try (var in = new ByteBuffersInputStream(buffers)) {
                return unmarshal(in, charset, type);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy