001package io.avaje.jsonb.stream;
002
003import io.avaje.jsonb.JsonReader;
004import io.avaje.jsonb.JsonWriter;
005import io.avaje.jsonb.spi.*;
006
007import java.io.*;
008import java.nio.charset.StandardCharsets;
009
010/**
011 * Default implementation of JsonStreamAdapter provided with Jsonb.
012 */
013public final class JsonStream implements JsonStreamAdapter {
014
015  /**
016   * Used to build JsonStream with custom settings.
017   */
018  public static final class Builder {
019
020    private boolean serializeNulls;
021    private boolean serializeEmpty;
022    private boolean failOnUnknown;
023
024    /**
025     * Set to true to serialize nulls. Defaults to false.
026     */
027    public Builder serializeNulls(boolean serializeNulls) {
028      this.serializeNulls = serializeNulls;
029      return this;
030    }
031
032    /**
033     * Set to true to serialize empty collections. Defaults to false.
034     */
035    public Builder serializeEmpty(boolean serializeEmpty) {
036      this.serializeEmpty = serializeEmpty;
037      return this;
038    }
039
040    /**
041     * Set to true to fail on unknown properties. Defaults to false.
042     */
043    public Builder failOnUnknown(boolean failOnUnknown) {
044      this.failOnUnknown = failOnUnknown;
045      return this;
046    }
047
048    /**
049     * Build and return the JsonStream.
050     */
051    public JsonStream build() {
052      return new JsonStream(serializeNulls, serializeEmpty, failOnUnknown);
053    }
054  }
055
056  private final boolean serializeNulls;
057  private final boolean serializeEmpty;
058  private final boolean failOnUnknown;
059
060  /**
061   * Create with the given default configuration.
062   */
063  public JsonStream() {
064    this(false, false, false);
065  }
066
067  /**
068   * Create additionally providing the jsonFactory.
069   */
070  public JsonStream(boolean serializeNulls, boolean serializeEmpty, boolean failOnUnknown) {
071    this.serializeNulls = serializeNulls;
072    this.serializeEmpty = serializeEmpty;
073    this.failOnUnknown = failOnUnknown;
074  }
075
076  /**
077   * Return a new builder to create a JsonStream with custom configuration.
078   *
079   * <pre>{@code
080   *
081   * var jsonStream = JsonStream.builder()
082   *   .serializeNulls(true)
083   *   .build();
084   *
085   * }</pre>
086   */
087  public static Builder builder() {
088    return new Builder();
089  }
090
091  @Override
092  public PropertyNames properties(String... names) {
093    return JsonNames.of(names);
094  }
095
096  @Override
097  public JsonReader reader(String json) {
098    return reader(json.getBytes(StandardCharsets.UTF_8));
099  }
100
101  @Override
102  public JsonReader reader(byte[] json) {
103    JsonParser parser = Recycle.parser(json);
104    return new JsonReadAdapter(parser, failOnUnknown);
105  }
106
107  @Override
108  public JsonReader reader(Reader reader) {
109    // TODO: Could recycle encoder and buffer
110    return reader(new ReaderInputStream(reader, StandardCharsets.UTF_8));
111  }
112
113  @Override
114  public JsonReader reader(InputStream inputStream) {
115    JsonParser parser = Recycle.parser(inputStream);
116    return new JsonReadAdapter(parser, failOnUnknown);
117  }
118
119  @Override
120  public JsonWriter writer(Writer writer) {
121    // TODO: Could recycle buffer used
122    return writer(new WriterOutputStream(writer, StandardCharsets.UTF_8));
123  }
124
125  @Override
126  public JsonWriter writer(OutputStream outputStream) {
127    return wrap(gen(outputStream));
128  }
129
130  @Override
131  public BufferedJsonWriter bufferedWriter() {
132    JsonGenerator generator = Recycle.generator();
133    return new BufferedWriter(wrap(generator), generator);
134  }
135
136  @Override
137  public BytesJsonWriter bufferedWriterAsBytes() {
138    JsonGenerator generator = Recycle.generator();
139    return new BytesWriter(wrap(generator), generator);
140  }
141
142  private JsonGenerator gen(OutputStream outputStream) {
143    return Recycle.generator(outputStream);
144  }
145
146  private JsonWriteAdapter wrap(JsonGenerator generator) {
147    return new JsonWriteAdapter(generator, serializeNulls, serializeEmpty);
148  }
149
150  private static class BufferedWriter extends DelegateJsonWriter implements BufferedJsonWriter {
151
152    private final JsonGenerator generator;
153
154    BufferedWriter(JsonWriteAdapter delegate, JsonGenerator generator) {
155      super(delegate);
156      this.generator = generator;
157    }
158
159    @Override
160    public String result() {
161      return generator.toString();
162    }
163  }
164
165  private static class BytesWriter extends DelegateJsonWriter implements BytesJsonWriter {
166
167    private final JsonGenerator generator;
168
169    public BytesWriter(JsonWriteAdapter delegate, JsonGenerator generator) {
170      super(delegate);
171      this.generator = generator;
172    }
173
174    @Override
175    public byte[] result() {
176      return generator.toByteArray();
177    }
178  }
179}