1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.databind.io.json;
7   
8   import com.fasterxml.jackson.core.JsonFactory;
9   import com.fasterxml.jackson.core.JsonGenerator;
10  import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
11  
12  import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
13  import gov.nist.secauto.metaschema.core.model.IBoundObject;
14  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
15  import gov.nist.secauto.metaschema.databind.io.AbstractSerializer;
16  import gov.nist.secauto.metaschema.databind.io.SerializationFeature;
17  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
18  
19  import java.io.IOException;
20  import java.io.Writer;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  import nl.talsmasoftware.lazy4j.Lazy;
24  
25  public class DefaultJsonSerializer<CLASS extends IBoundObject>
26      extends AbstractSerializer<CLASS> {
27    private Lazy<JsonFactory> factory;
28  
29    /**
30     * Construct a new Module binding-based deserializer that reads JSON-based
31     * Module content.
32     *
33     * @param definition
34     *          the assembly class binding describing the Java objects this
35     *          deserializer parses data into
36     */
37    public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) {
38      super(definition);
39      resetFactory();
40    }
41  
42    protected final void resetFactory() {
43      this.factory = Lazy.lazy(this::newFactoryInstance);
44    }
45  
46    @Override
47    protected void configurationChanged(IMutableConfiguration<SerializationFeature<?>> config) {
48      super.configurationChanged(config);
49      resetFactory();
50    }
51  
52    /**
53     * Constructs a new JSON factory.
54     * <p>
55     * Subclasses can override this method to create a JSON factory with a specific
56     * configuration.
57     *
58     * @return the factory
59     */
60    @NonNull
61    protected JsonFactory newFactoryInstance() {
62      return JsonFactoryFactory.instance();
63    }
64  
65    @NonNull
66    private JsonFactory getJsonFactory() {
67      return ObjectUtils.notNull(factory.get());
68    }
69  
70    @SuppressWarnings("resource")
71    @NonNull
72    private JsonGenerator newJsonGenerator(@NonNull Writer writer) throws IOException {
73      JsonFactory factory = getJsonFactory();
74      return ObjectUtils.notNull(factory.createGenerator(writer)
75          .setPrettyPrinter(new DefaultPrettyPrinter()));
76    }
77  
78    @Override
79    public void serialize(IBoundObject data, Writer writer) throws IOException {
80      try (JsonGenerator generator = newJsonGenerator(writer)) {
81        IBoundDefinitionModelAssembly definition = getDefinition();
82  
83        boolean serializeRoot = get(SerializationFeature.SERIALIZE_ROOT);
84        if (serializeRoot) {
85          // first write the initial START_OBJECT
86          generator.writeStartObject();
87  
88          generator.writeFieldName(definition.getRootJsonName());
89        }
90  
91        MetaschemaJsonWriter jsonWriter = new MetaschemaJsonWriter(generator);
92        jsonWriter.write(definition, data);
93  
94        if (serializeRoot) {
95          generator.writeEndObject();
96        }
97      }
98    }
99  }