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  
24  public class DefaultJsonSerializer<CLASS extends IBoundObject>
25      extends AbstractSerializer<CLASS> {
26    private JsonFactory jsonFactory;
27  
28    /**
29     * Construct a new Module binding-based deserializer that reads JSON-based
30     * Module content.
31     *
32     * @param definition
33     *          the assembly class binding describing the Java objects this
34     *          deserializer parses data into
35     */
36    public DefaultJsonSerializer(@NonNull IBoundDefinitionModelAssembly definition) {
37      super(definition);
38    }
39  
40    /**
41     * Constructs a new JSON factory.
42     * <p>
43     * Subclasses can override this method to create a JSON factory with a specific
44     * configuration.
45     *
46     * @return the factory
47     */
48    @NonNull
49    protected JsonFactory getJsonFactoryInstance() {
50      return JsonFactoryFactory.instance();
51    }
52  
53    @SuppressWarnings("PMD.NullAssignment")
54    @Override
55    protected void configurationChanged(IMutableConfiguration<SerializationFeature<?>> config) {
56      synchronized (this) {
57        jsonFactory = null;
58      }
59    }
60  
61    @NonNull
62    private JsonFactory getJsonFactory() {
63      synchronized (this) {
64        if (jsonFactory == null) {
65          jsonFactory = getJsonFactoryInstance();
66        }
67        assert jsonFactory != null;
68        return jsonFactory;
69      }
70    }
71  
72    @SuppressWarnings("resource")
73    @NonNull
74    private JsonGenerator newJsonGenerator(@NonNull Writer writer) throws IOException {
75      JsonFactory factory = getJsonFactory();
76      return ObjectUtils.notNull(factory.createGenerator(writer)
77          .setPrettyPrinter(new DefaultPrettyPrinter()));
78    }
79  
80    @Override
81    public void serialize(IBoundObject data, Writer writer) throws IOException {
82      try (JsonGenerator generator = newJsonGenerator(writer)) {
83        IBoundDefinitionModelAssembly definition = getDefinition();
84  
85        boolean serializeRoot = get(SerializationFeature.SERIALIZE_ROOT);
86        if (serializeRoot) {
87          // first write the initial START_OBJECT
88          generator.writeStartObject();
89  
90          generator.writeFieldName(definition.getRootJsonName());
91        }
92  
93        MetaschemaJsonWriter jsonWriter = new MetaschemaJsonWriter(generator);
94        jsonWriter.write(definition, data);
95  
96        if (serializeRoot) {
97          generator.writeEndObject();
98        }
99      }
100   }
101 }