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

ratpack.gson.Gson Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2018 the original author or 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
 *
 *    http://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 ratpack.gson;

import com.google.common.reflect.TypeToken;
import com.google.gson.JsonElement;
import com.google.gson.stream.JsonWriter;
import io.netty.buffer.Unpooled;
import org.reactivestreams.Publisher;
import ratpack.api.Nullable;
import ratpack.func.Function;
import ratpack.gson.internal.DefaultGsonParseOpts;
import ratpack.gson.internal.DefaultGsonRender;
import ratpack.http.ResponseChunks;
import ratpack.http.internal.HttpHeaderConstants;
import ratpack.parse.Parse;
import ratpack.registry.Registry;
import ratpack.stream.StreamMapper;
import ratpack.stream.Streams;
import ratpack.stream.WriteStream;

import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;

/**
 * Support for rendering and parsing JSON using Google's Gson library.
 * @since 1.6
 */
public abstract class Gson {

  private Gson() {
  }

  /**
   * Creates a {@link ratpack.handling.Context#render renderable object} to render the given object as JSON.
   * 

* The given object will be converted to JSON using a {@link com.google.gson.Gson} instance obtained from the context registry. *

* See the rendering section for usage examples. * * @param object the object to render as JSON * @return a renderable wrapper for the given object */ public static GsonRender json(Object object) { return new DefaultGsonRender(object, null); } /** * Creates a {@link ratpack.handling.Context#render renderable object} to render the given object as JSON. *

* The given object will be converted to JSON using the given {@link com.google.gson.Gson}. * If it is {@code null}, a {@code Gson} instance will be obtained from the context registry. *

* See the rendering section for usage examples. * * @param object the object to render as JSON * @param gson the Gson instance to use to serialize the object to JSON * @return a renderable wrapper for the given object */ public static GsonRender json(Object object, @Nullable com.google.gson.Gson gson) { return new DefaultGsonRender(object, gson); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into a {@link JsonElement}. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using a {@link com.google.gson.Gson} obtained from the context registry. *

* See the parsing section for usage examples. * * @return a parse object */ public static Parse jsonElement() { return jsonElement(null); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into a {@link JsonElement}. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using the given {@link com.google.gson.Gson}. * If it is {@code null}, a Gson will be obtained from the context registry. *

* See the parsing section for usage examples. * * @param gson the Gson instance to use to parse the JSON * @return a parse object */ public static Parse jsonElement(@Nullable com.google.gson.Gson gson) { return fromJson(JsonElement.class, gson); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into the given type. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using a {@link com.google.gson.Gson} obtained from the context registry. *

* See the parsing section for usage examples. * * @param type the type of object to deserialize the JSON into * @param the type of object to deserialize the JSON into * @return a parse object */ public static Parse fromJson(Class type) { return fromJson(type, null); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into the given type. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using a {@link com.google.gson.Gson} obtained from the context registry. *

* See the parsing section for usage examples. * * @param type the type of object to deserialize the JSON into * @param the type of object to deserialize the JSON into * @return a parse object */ public static Parse fromJson(TypeToken type) { return fromJson(type, null); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into the given type. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using the given {@link com.google.gson.Gson}. * If it is {@code null}, a Gson instance will be obtained from the context registry. *

* See the parsing section for usage examples. * * @param type the type of object to deserialize the JSON into * @param gson the Gson instance to use to convert the JSON into a Java object * @param the type of object to deserialize the JSON into * @return a parse object */ public static Parse fromJson(Class type, @Nullable com.google.gson.Gson gson) { return Parse.of(type, new DefaultGsonParseOpts(gson)); } /** * Creates a {@link ratpack.handling.Context#parse parseable object} to parse a request body into the given type. *

* The corresponding parser for this type requires the request content type to be {@code "application/json"}. *

* The request body will be parsed using the given {@link com.google.gson.Gson}. * If it is {@code null}, a Gson instance will be obtained from the context registry. *

* See the parsing section for usage examples. * * @param type the type of object to deserialize the JSON into * @param gson the Gson instance to use to convert the JSON into a Java object * @param the type of object to deserialize the JSON into * @return a parse object */ public static Parse fromJson(TypeToken type, @Nullable com.google.gson.Gson gson) { return Parse.of(type, new DefaultGsonParseOpts(gson)); } /** * Renders a data stream as a JSON list, directly streaming the JSON. *

* This method differs from rendering a list of items using {@link #json(Object) json(someList)} in that data is * written to the response as chunks, and is streamed. *

* If stream can be very large without using considerable memory as the JSON is streamed incrementally in chunks. * This does mean that if on object-to-JSON conversion fails midway through the stream, then the output JSON will be malformed due to being incomplete. * If the publisher emits an error, the response will be terminated and no more JSON will be sent. *

{@code
   * import ratpack.gson.GsonModule;
   * import ratpack.guice.Guice;
   * import ratpack.test.embed.EmbeddedApp;
   * import ratpack.http.client.ReceivedResponse;
   * import ratpack.stream.Streams;
   * import org.reactivestreams.Publisher;
   *
   * import java.util.Arrays;
   *
   * import static ratpack.gson.Gson.chunkedJsonList;
   * import static org.junit.Assert.*;
   *
   * public class Example {
   *   public static void main(String... args) throws Exception {
   *     EmbeddedApp.of(s -> s
   *       .registry(Guice.registry(b -> b.module(GsonModule.class)))
   *       .handlers(chain ->
   *         chain.get(ctx -> {
   *           Publisher ints = Streams.publish(Arrays.asList(1, 2, 3));
   *           ctx.render(chunkedJsonList(ctx, ints));
   *         })
   *       )
   *     ).test(httpClient -> {
   *       ReceivedResponse response = httpClient.get();
   *       assertEquals("[1,2,3]", response.getBody().getText()); // body was streamed in chunks
   *       assertEquals("application/json", response.getBody().getContentType().getType());
   *     });
   *   }
   * }
   * }
*

* Items of the stream will be converted to JSON by an {@link com.google.gson.Gson} obtained from the given registry. *

* This method uses {@link Streams#streamMap(Publisher, StreamMapper)} to consume the given stream. * * @param registry the registry to obtain the object mapper from * @param stream the stream to render * @param the type of item in the stream * @return a renderable object * @see Streams#streamMap(Publisher, StreamMapper) */ public static ResponseChunks chunkedJsonList(Registry registry, Publisher stream) { return chunkedJsonList(registry.get(com.google.gson.Gson.class), stream); } /** * Renders a data stream as a JSON list, directly streaming the JSON. *

* Identical to {@link #chunkedJsonList(Registry, Publisher)}, except uses the given Gson instance instead of obtaining one from the registry. * * @param gson the Gson instance to use to convert stream items to their JSON representation * @param stream the stream to render * @param the type of item in the stream * @return a renderable object * @see #chunkedJsonList(Registry, Publisher) */ public static ResponseChunks chunkedJsonList(com.google.gson.Gson gson, Publisher stream) { return ResponseChunks.bufferChunks(HttpHeaderConstants.JSON, Streams.streamMap(stream, (s, out) -> { JsonWriter writer = gson.newJsonWriter(new Writer() { @Override public void write(char[] b, int off, int len) throws IOException { out.item(Unpooled.copiedBuffer(b, off, len, Charset.defaultCharset())); } @Override public void flush() throws IOException { } @Override public void close() throws IOException { } }); writer.beginArray(); return new WriteStream() { @Override public void item(T item) { try { gson.toJson(item, item.getClass(), writer); } catch (Exception e) { s.cancel(); out.error(e); } } @Override public void error(Throwable throwable) { out.error(throwable); } @Override public void complete() { try { writer.endArray(); writer.close(); out.complete(); } catch (IOException e) { out.error(e); } } }; })); } /** * Creates a mapping function that returns the JSON representation as a string of the input object. *

* An {@link com.google.gson.Gson} instance is obtained from the given registry eagerly. * The returned function uses the {@link com.google.gson.Gson#toJson(Object)} method to convert the input object to JSON. *

{@code
   * import ratpack.gson.GsonModule;
   * import ratpack.guice.Guice;
   * import ratpack.exec.Promise;
   * import ratpack.test.embed.EmbeddedApp;
   * import ratpack.http.client.ReceivedResponse;
   *
   * import java.util.Arrays;
   *
   * import static ratpack.gson.Gson.toJson;
   * import static java.util.Collections.singletonMap;
   * import static org.junit.Assert.*;
   *
   * public class Example {
   *   public static void main(String... args) throws Exception {
   *     EmbeddedApp.of(s -> s
   *       .registry(Guice.registry(b -> b.module(GsonModule.class)))
   *       .handlers(chain -> chain
   *         .get(ctx ->
   *           Promise.value(singletonMap("foo", "bar"))
   *             .map(toJson(ctx))
   *             .then(ctx::render)
   *         )
   *       )
   *     ).test(httpClient -> {
   *       assertEquals("{\"foo\":\"bar\"}", httpClient.getText());
   *     });
   *   }
   * }
   * }
*

* Note that in the above example, it would have been better to just render the result of the blocking call. * Doing so would be more convenient and also set the correct {@code "Content-Type"} header. * This method can be useful when sending the JSON somewhere else than directly to the response, or when {@link Streams#map(Publisher, Function) mapping streams}. * * @param registry the registry to obtain the {@link com.google.gson.Gson} from * @param the type of object to convert to JSON * @return a function that converts objects to their JSON string representation */ public static Function toJson(Registry registry) { return obj -> registry.get(com.google.gson.Gson.class).toJson(obj); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy