/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.jooby.json; import static java.util.Objects.requireNonNull; import java.util.function.BiConsumer; import java.util.function.Consumer; import org.jooby.Env; import org.jooby.Jooby; import org.jooby.MediaType; import org.jooby.Parser; import org.jooby.Renderer; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.inject.Binder; import com.google.inject.multibindings.Multibinder; import com.typesafe.config.Config; /** * JSON support via <a href="https://github.com/google/gson">Gson</a> library. * * <h1>exposes</h1> * * <ul> * <li>A {@link Gson}</li> * <li>A {@link Parser}</li> * <li>A {@link Renderer}</li> * </ul> * * <h1>usage</h1> * * <pre> * { * use(new Gzon()); * * // sending * get("/my-api", req {@literal ->} new MyObject()); * * // receiving a json body * post("/my-api", req {@literal ->} { * MyObject obj = req.body(MyObject.class); * return obj; * }); * * // direct access to Gson * get("/access", req {@literal ->} { * Gson gson = req.require(Gson.class); * // ... * }); * } * </pre> * * <h1>configuration</h1> * * <p> * If you need a special setting or configuration for your {@link Gson}: * </p> * * <pre> * { * use(new Gzon().doWith(builder {@literal ->} { * builder.setPrettyPrint(); * // ... * }); * } * </pre> * * @author edgar * @since 0.6.0 */ public class Gzon implements Jooby.Module { private MediaType type; private BiConsumer<GsonBuilder, Config> configurer; /** * Creates a new {@link Gson}. * * @param type {@link MediaType} to use. */ public Gzon(final MediaType type) { this.type = requireNonNull(type, "Media type is required."); } /** * Creates a new {@link Gson} and set type to: {@link MediaType#json}. * */ public Gzon() { this(MediaType.json); } /** * Configurer callback. * * <pre> * { * use(new Gzon().doWith(builder {@literal ->} { * builder.setPrettyPrint(); * // ... * }); * } * </pre> * * @param configurer A callback. * @return This instance. */ public Gzon doWith(final BiConsumer<GsonBuilder, Config> configurer) { this.configurer = requireNonNull(configurer, "Configurer callback is required."); return this; } /** * Configurer callback. * * <pre> * { * use(new Gzon().doWith((builder, config) {@literal ->} { * builder.setPrettyPrint(); * // ... * }); * } * </pre> * * @param configurer A callback. * @return This instance. */ public Gzon doWith(final Consumer<GsonBuilder> configurer) { requireNonNull(configurer, "Configurer callback is required."); this.configurer = (gson, conf) -> configurer.accept(gson); return this; } @Override public void configure(final Env env, final Config config, final Binder binder) { GsonBuilder gsonb = new GsonBuilder(); if (configurer != null) { configurer.accept(gsonb, config); } Gson gson = gsonb.create(); binder.bind(Gson.class).toInstance(gson); Multibinder.newSetBinder(binder, Parser.class).addBinding() .toInstance(new GsonParser(type, gson)); Multibinder.newSetBinder(binder, Renderer.class).addBinding() .toInstance(new GsonRenderer(type, gson)); } }