001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.json5;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import org.apache.juneau.commons.collections.*;
022import org.apache.juneau.marshall.json.*;
023
024/**
025 * Serializes POJO models to Simplified JSON.
026 *
027 * <h5 class='topic'>Media types</h5>
028 *
029 * Handles <c>Accept</c> types:  <bc>application/json, text/json</bc>
030 * <p>
031 * Produces <c>Content-Type</c> types:  <bc>application/json5</bc>
032 *
033 * <h5 class='topic'>Description</h5>
034 * <p>
035 *    This is a JSON serializer that uses simplified notation:
036 * <ul class='spaced-list'>
037 *    <li>Lax quoting of JSON attribute names.
038 *    <li>Single quotes.
039 * </ul>
040 *
041 * <h5 class='figure'>Example output (Map of name/age):</h5>
042 * <p class='bjson'>
043 *    {name:<js>"Alice"</js>,age:30}
044 * </p>
045 *
046 * <h5 class='figure'>Complex (nested object + array):</h5>
047 * <p class='bjson'>
048 *    {name:<js>"Alice"</js>,age:30,address:{street:<js>"123 Main St"</js>,city:<js>"Boston"</js>,state:<js>"MA"</js>},tags:[<js>"a"</js>,<js>"b"</js>,<js>"c"</js>]}
049 * </p>
050 *
051 * <h5 class='section'>Notes:</h5><ul>
052 *    <li class='note'>This class is thread safe and reusable.
053 * </ul>
054 *
055 * <h5 class='section'>See Also:</h5><ul>
056 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JsonSupport">JSON</a>
057 * </ul>
058 */
059@SuppressWarnings({
060   "java:S110", // Inheritance depth acceptable
061   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
062   "java:S9149" // Per-format static factories intentionally shadow the parent's.
063})
064public class Json5Serializer extends JsonSerializer {
065
066   /**
067    * Builder class.
068    */
069   public static class Builder extends JsonSerializer.Builder<Builder> {
070
071      private static final Cache<HashKey,Json5Serializer> CACHE = Cache.of(HashKey.class, Json5Serializer.class).build();
072
073      /**
074       * Constructor, default settings.
075       */
076      protected Builder() {
077         quoteChar('\'')
078            .produces("application/json5")
079            .accept("application/json5,text/json5,application/json;q=0.9,text/json;q=0.9");
080      }
081
082      /**
083       * Copy constructor.
084       *
085       * @param copyFrom The builder to copy from.
086       *    <br>Cannot be <jk>null</jk>.
087       */
088      protected Builder(Builder copyFrom) {
089         super(reqnn("copyFrom", copyFrom));
090      }
091
092      /**
093       * Copy constructor.
094       *
095       * @param copyFrom The bean to copy from.
096       *    <br>Cannot be <jk>null</jk>.
097       */
098      protected Builder(Json5Serializer copyFrom) {
099         super(reqnn("copyFrom", copyFrom));
100      }
101
102      @Override /* Overridden from Context.Builder<?> */
103      public Json5Serializer build() {
104         return cache(CACHE).build(Json5Serializer.class);
105      }
106
107      @Override /* Overridden from Context.Builder<?> */
108      public Builder copy() {
109         return new Builder(this);
110      }
111
112
113   }
114
115   /** Default serializer, single quotes, simple mode, with whitespace. */
116   public static class Readable extends Json5Serializer {
117
118      /**
119       * Constructor.
120       *
121       * @param builder The builder for this object.
122       */
123      public Readable(Builder builder) {
124         super(builder.useWhitespace());
125      }
126   }
127
128   /** Default serializer, single quotes. */
129   public static final Json5Serializer DEFAULT = new Json5Serializer(create());
130
131   /** Default serializer, single quotes, with whitespace. */
132   public static final Json5Serializer DEFAULT_READABLE = new Readable(create());
133
134   /**
135    * Creates a new builder for this object.
136    *
137    * @return A new builder.
138    */
139   public static Builder create() {
140      return new Builder();
141   }
142
143   /**
144    * Constructor.
145    *
146    * @param builder The builder for this object.
147    */
148   public Json5Serializer(Builder builder) {
149      super(builder);
150   }
151
152   /**
153    * Constructor.
154    *
155    * @param builder The builder for this object.
156    */
157   public Json5Serializer(JsonSerializer.Builder<?> builder) {
158      super(builder.quoteChar('\''));
159   }
160
161   @Override /* Overridden from Context */
162   public Builder copy() {
163      return new Builder(this);
164   }
165
166   @Override /* Overridden from Context */
167   public Json5SerializerSession.Builder createSession() {
168      return Json5SerializerSession.create(this);
169   }
170
171   @Override /* Overridden from Context */
172   public Json5SerializerSession getSession() { return createSession().build(); }
173
174}