001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.http.converter.json;
018
019import java.io.Reader;
020import java.io.Writer;
021import java.lang.reflect.ParameterizedType;
022import java.lang.reflect.Type;
023
024import javax.json.bind.Jsonb;
025import javax.json.bind.JsonbBuilder;
026import javax.json.bind.JsonbConfig;
027
028import org.springframework.lang.Nullable;
029import org.springframework.util.Assert;
030
031/**
032 * Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
033 * that can read and write JSON using the
034 * <a href="http://json-b.net/">JSON Binding API</a>.
035 *
036 * <p>This converter can be used to bind to typed beans or untyped {@code HashMap}s.
037 * By default, it supports {@code application/json} and {@code application/*+json} with
038 * {@code UTF-8} character set.
039 *
040 * @author Juergen Hoeller
041 * @since 5.0
042 * @see javax.json.bind.Jsonb
043 * @see javax.json.bind.JsonbBuilder
044 * @see #setJsonb
045 */
046public class JsonbHttpMessageConverter extends AbstractJsonHttpMessageConverter {
047
048        private Jsonb jsonb;
049
050
051        /**
052         * Construct a new {@code JsonbHttpMessageConverter} with default configuration.
053         */
054        public JsonbHttpMessageConverter() {
055                this(JsonbBuilder.create());
056        }
057
058        /**
059         * Construct a new {@code JsonbHttpMessageConverter} with the given configuration.
060         * @param config the {@code JsonbConfig} for the underlying delegate
061         */
062        public JsonbHttpMessageConverter(JsonbConfig config) {
063                this.jsonb = JsonbBuilder.create(config);
064        }
065
066        /**
067         * Construct a new {@code JsonbHttpMessageConverter} with the given delegate.
068         * @param jsonb the Jsonb instance to use
069         */
070        public JsonbHttpMessageConverter(Jsonb jsonb) {
071                Assert.notNull(jsonb, "A Jsonb instance is required");
072                this.jsonb = jsonb;
073        }
074
075
076        /**
077         * Set the {@code Jsonb} instance to use.
078         * If not set, a default {@code Jsonb} instance will be created.
079         * <p>Setting a custom-configured {@code Jsonb} is one way to take further
080         * control of the JSON serialization process.
081         * @see #JsonbHttpMessageConverter(Jsonb)
082         * @see #JsonbHttpMessageConverter(JsonbConfig)
083         * @see JsonbBuilder
084         */
085        public void setJsonb(Jsonb jsonb) {
086                Assert.notNull(jsonb, "A Jsonb instance is required");
087                this.jsonb = jsonb;
088        }
089
090        /**
091         * Return the configured {@code Jsonb} instance for this converter.
092         */
093        public Jsonb getJsonb() {
094                return this.jsonb;
095        }
096
097
098        @Override
099        protected Object readInternal(Type resolvedType, Reader reader) throws Exception {
100                return getJsonb().fromJson(reader, resolvedType);
101        }
102
103        @Override
104        protected void writeInternal(Object object, @Nullable Type type, Writer writer) throws Exception {
105                if (type instanceof ParameterizedType) {
106                        getJsonb().toJson(object, type, writer);
107                }
108                else {
109                        getJsonb().toJson(object, writer);
110                }
111        }
112
113}