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.JsonParser;
10  
11  import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
12  import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
13  import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory;
14  import gov.nist.secauto.metaschema.core.model.IBoundObject;
15  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
16  import gov.nist.secauto.metaschema.databind.io.AbstractDeserializer;
17  import gov.nist.secauto.metaschema.databind.io.DeserializationFeature;
18  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
19  
20  import java.io.IOException;
21  import java.io.Reader;
22  import java.net.URI;
23  
24  import edu.umd.cs.findbugs.annotations.NonNull;
25  
26  public class DefaultJsonDeserializer<CLASS extends IBoundObject>
27      extends AbstractDeserializer<CLASS> {
28    private JsonFactory jsonFactory;
29  
30    /**
31     * Construct a new JSON deserializer that will parse the bound class identified
32     * by the {@code classBinding}.
33     *
34     * @param definition
35     *          the bound class information for the Java type this deserializer is
36     *          operating on
37     */
38    public DefaultJsonDeserializer(@NonNull IBoundDefinitionModelAssembly definition) {
39      super(definition);
40    }
41  
42    /**
43     * Get a JSON factory instance.
44     * <p>
45     * This method can be used by sub-classes to create a customized factory
46     * instance.
47     *
48     * @return the factory
49     */
50    @NonNull
51    protected JsonFactory newJsonFactoryInstance() {
52      return JsonFactoryFactory.instance();
53    }
54  
55    /**
56     * Get the parser factory associated with this deserializer.
57     *
58     * @return the factory instance
59     */
60    @NonNull
61    protected JsonFactory getJsonFactory() {
62      synchronized (this) {
63        if (jsonFactory == null) {
64          jsonFactory = newJsonFactoryInstance();
65        }
66        assert jsonFactory != null;
67        return jsonFactory;
68      }
69    }
70  
71    /**
72     * Using the managed JSON factory, create a new JSON parser instance using the
73     * provided reader.
74     *
75     * @param reader
76     *          the reader for the parser to read data from
77     * @return the new parser
78     * @throws IOException
79     *           if an error occurred while creating the parser
80     */
81    @SuppressWarnings("resource") // reader resource not owned
82    @NonNull
83    protected final JsonParser newJsonParser(@NonNull Reader reader) throws IOException {
84      return ObjectUtils.notNull(getJsonFactory().createParser(reader));
85    }
86  
87    @Override
88    protected INodeItem deserializeToNodeItemInternal(@NonNull Reader reader, @NonNull URI documentUri)
89        throws IOException {
90      INodeItem retval;
91      try (JsonParser jsonParser = newJsonParser(reader)) {
92        MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser);
93        IBoundDefinitionModelAssembly definition = getDefinition();
94        IConfiguration<DeserializationFeature<?>> configuration = getConfiguration();
95  
96        if (definition.isRoot()
97            && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) {
98          // now parse the root property
99          CLASS value = ObjectUtils.requireNonNull(parser.readObjectRoot(definition, definition.getRootJsonName()));
100 
101         retval = INodeItemFactory.instance().newDocumentNodeItem(definition, documentUri, value);
102       } else {
103         // read the top-level definition
104         CLASS value = ObjectUtils.asType(parser.readObject(definition));
105 
106         retval = INodeItemFactory.instance().newAssemblyNodeItem(definition, documentUri, value);
107       }
108       return retval;
109     }
110   }
111 
112   @Override
113   public CLASS deserializeToValueInternal(@NonNull Reader reader, @NonNull URI documentUri) throws IOException {
114     try (JsonParser jsonParser = newJsonParser(reader)) {
115       MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser);
116       IBoundDefinitionModelAssembly definition = getDefinition();
117       IConfiguration<DeserializationFeature<?>> configuration = getConfiguration();
118 
119       CLASS retval;
120       if (definition.isRoot()
121           && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) {
122 
123         // now parse the root property
124         retval = ObjectUtils.requireNonNull(parser.readObjectRoot(definition, definition.getRootJsonName()));
125       } else {
126         // read the top-level definition
127         retval = ObjectUtils.asType(ObjectUtils.requireNonNull(
128             parser.readObject(definition)));
129       }
130       return retval;
131     }
132   }
133 }