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;
023
024public class DefaultJsonSerializer<CLASS extends IBoundObject>
025    extends AbstractSerializer<CLASS> {
026  private JsonFactory jsonFactory;
027
028  /**
029   * Construct a new Module binding-based deserializer that reads JSON-based
030   * Module content.
031   *
032   * @param definition
033   *          the assembly class binding describing the Java objects this
034   *          deserializer parses data into
035   */
036  public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) {
037    super(definition);
038  }
039
040  /**
041   * Constructs a new JSON factory.
042   * <p>
043   * Subclasses can override this method to create a JSON factory with a specific
044   * configuration.
045   *
046   * @return the factory
047   */
048  @NonNull
049  protected JsonFactory getJsonFactoryInstance() {
050    return JsonFactoryFactory.instance();
051  }
052
053  @SuppressWarnings("PMD.NullAssignment")
054  @Override
055  protected void configurationChanged(IMutableConfiguration<SerializationFeature<?>> config) {
056    synchronized (this) {
057      jsonFactory = null;
058    }
059  }
060
061  @NonNull
062  private JsonFactory getJsonFactory() {
063    synchronized (this) {
064      if (jsonFactory == null) {
065        jsonFactory = getJsonFactoryInstance();
066      }
067      assert jsonFactory != null;
068      return jsonFactory;
069    }
070  }
071
072  @SuppressWarnings("resource")
073  @NonNull
074  private JsonGenerator newJsonGenerator(@NonNull Writer writer) throws IOException {
075    JsonFactory factory = getJsonFactory();
076    return ObjectUtils.notNull(factory.createGenerator(writer)
077        .setPrettyPrinter(new DefaultPrettyPrinter()));
078  }
079
080  @Override
081  public void serialize(IBoundObject data, Writer writer) throws IOException {
082    try (JsonGenerator generator = newJsonGenerator(writer)) {
083      IBoundDefinitionModelAssembly definition = getDefinition();
084
085      boolean serializeRoot = get(SerializationFeature.SERIALIZE_ROOT);
086      if (serializeRoot) {
087        // first write the initial START_OBJECT
088        generator.writeStartObject();
089
090        generator.writeFieldName(definition.getRootJsonName());
091      }
092
093      MetaschemaJsonWriter jsonWriter = new MetaschemaJsonWriter(generator);
094      jsonWriter.write(definition, data);
095
096      if (serializeRoot) {
097        generator.writeEndObject();
098      }
099    }
100  }
101}