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    try {
116      JsonParser parser = Recycle.parser(inputStream);
117      return new JsonReadAdapter(parser, failOnUnknown);
118    } catch (IOException e) {
119      throw new UncheckedIOException(e);
120    }
121  }
122
123  @Override
124  public JsonWriter writer(Writer writer) {
125    // TODO: Could recycle buffer used
126    return writer(new WriterOutputStream(writer, StandardCharsets.UTF_8));
127  }
128
129  @Override
130  public JsonWriter writer(OutputStream outputStream) {
131    return wrap(gen(outputStream));
132  }
133
134  @Override
135  public BufferedJsonWriter bufferedWriter() {
136    JsonGenerator generator = Recycle.generator();
137    return new BufferedWriter(wrap(generator), generator);
138  }
139
140  @Override
141  public BytesJsonWriter bufferedWriterAsBytes() {
142    JsonGenerator generator = Recycle.generator();
143    return new BytesWriter(wrap(generator), generator);
144  }
145
146  private JsonGenerator gen(OutputStream outputStream) {
147    return Recycle.generator(outputStream);
148  }
149
150  private JsonWriteAdapter wrap(JsonGenerator generator) {
151    return new JsonWriteAdapter(generator, serializeNulls, serializeEmpty);
152  }
153
154  private static class BufferedWriter extends DelegateJsonWriter implements BufferedJsonWriter {
155
156    private final JsonGenerator generator;
157
158    BufferedWriter(JsonWriteAdapter delegate, JsonGenerator generator) {
159      super(delegate);
160      this.generator = generator;
161    }
162
163    @Override
164    public String result() {
165      return generator.toString();
166    }
167  }
168
169  private static class BytesWriter extends DelegateJsonWriter implements BytesJsonWriter {
170
171    private final JsonGenerator generator;
172
173    public BytesWriter(JsonWriteAdapter delegate, JsonGenerator generator) {
174      super(delegate);
175      this.generator = generator;
176    }
177
178    @Override
179    public byte[] result() {
180      return generator.toByteArray();
181    }
182  }
183}