001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.databind.io.json;
007
008import com.fasterxml.jackson.core.JsonFactory;
009import com.fasterxml.jackson.core.JsonGenerator;
010import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
011
012import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
013import gov.nist.secauto.metaschema.core.model.IBoundObject;
014import gov.nist.secauto.metaschema.core.util.ObjectUtils;
015import gov.nist.secauto.metaschema.databind.io.AbstractSerializer;
016import gov.nist.secauto.metaschema.databind.io.SerializationFeature;
017import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
018
019import java.io.IOException;
020import java.io.Writer;
021
022import edu.umd.cs.findbugs.annotations.NonNull;
023import nl.talsmasoftware.lazy4j.Lazy;
024
025public class DefaultJsonSerializer<CLASS extends IBoundObject>
026    extends AbstractSerializer<CLASS> {
027  private Lazy<JsonFactory> factory;
028
029  /**
030   * Construct a new Module binding-based deserializer that reads JSON-based
031   * Module content.
032   *
033   * @param definition
034   *          the assembly class binding describing the Java objects this
035   *          deserializer parses data into
036   */
037  public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) {
038    super(definition);
039    resetFactory();
040  }
041
042  protected final void resetFactory() {
043    this.factory = Lazy.lazy(this::newFactoryInstance);
044  }
045
046  @Override
047  protected void configurationChanged(IMutableConfiguration<SerializationFeature<?>> config) {
048    super.configurationChanged(config);
049    resetFactory();
050  }
051
052  /**
053   * Constructs a new JSON factory.
054   * <p>
055   * Subclasses can override this method to create a JSON factory with a specific
056   * configuration.
057   *
058   * @return the factory
059   */
060  @NonNull
061  protected JsonFactory newFactoryInstance() {
062    return JsonFactoryFactory.instance();
063  }
064
065  @NonNull
066  private JsonFactory getJsonFactory() {
067    return ObjectUtils.notNull(factory.get());
068  }
069
070  @SuppressWarnings("resource")
071  @NonNull
072  private JsonGenerator newJsonGenerator(@NonNull Writer writer) throws IOException {
073    JsonFactory factory = getJsonFactory();
074    return ObjectUtils.notNull(factory.createGenerator(writer)
075        .setPrettyPrinter(new DefaultPrettyPrinter()));
076  }
077
078  @Override
079  public void serialize(IBoundObject data, Writer writer) throws IOException {
080    try (JsonGenerator generator = newJsonGenerator(writer)) {
081      IBoundDefinitionModelAssembly definition = getDefinition();
082
083      boolean serializeRoot = get(SerializationFeature.SERIALIZE_ROOT);
084      if (serializeRoot) {
085        // first write the initial START_OBJECT
086        generator.writeStartObject();
087
088        generator.writeFieldName(definition.getRootJsonName());
089      }
090
091      MetaschemaJsonWriter jsonWriter = new MetaschemaJsonWriter(generator);
092      jsonWriter.write(definition, data);
093
094      if (serializeRoot) {
095        generator.writeEndObject();
096      }
097    }
098  }
099}