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.JsonParser; 010 011import gov.nist.secauto.metaschema.core.configuration.IConfiguration; 012import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; 013import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory; 014import gov.nist.secauto.metaschema.core.model.IBoundObject; 015import gov.nist.secauto.metaschema.core.util.ObjectUtils; 016import gov.nist.secauto.metaschema.databind.io.AbstractDeserializer; 017import gov.nist.secauto.metaschema.databind.io.DeserializationFeature; 018import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly; 019 020import java.io.IOException; 021import java.io.Reader; 022import java.net.URI; 023 024import edu.umd.cs.findbugs.annotations.NonNull; 025 026public class DefaultJsonDeserializer<CLASS extends IBoundObject> 027 extends AbstractDeserializer<CLASS> { 028 private JsonFactory jsonFactory; 029 030 /** 031 * Construct a new JSON deserializer that will parse the bound class identified 032 * by the {@code classBinding}. 033 * 034 * @param definition 035 * the bound class information for the Java type this deserializer is 036 * operating on 037 */ 038 public DefaultJsonDeserializer(@NonNull IBoundDefinitionModelAssembly definition) { 039 super(definition); 040 } 041 042 /** 043 * Get a JSON factory instance. 044 * <p> 045 * This method can be used by sub-classes to create a customized factory 046 * instance. 047 * 048 * @return the factory 049 */ 050 @NonNull 051 protected JsonFactory newJsonFactoryInstance() { 052 return JsonFactoryFactory.instance(); 053 } 054 055 /** 056 * Get the parser factory associated with this deserializer. 057 * 058 * @return the factory instance 059 */ 060 @NonNull 061 protected JsonFactory getJsonFactory() { 062 synchronized (this) { 063 if (jsonFactory == null) { 064 jsonFactory = newJsonFactoryInstance(); 065 } 066 assert jsonFactory != null; 067 return jsonFactory; 068 } 069 } 070 071 /** 072 * Using the managed JSON factory, create a new JSON parser instance using the 073 * provided reader. 074 * 075 * @param reader 076 * the reader for the parser to read data from 077 * @return the new parser 078 * @throws IOException 079 * if an error occurred while creating the parser 080 */ 081 @SuppressWarnings("resource") // reader resource not owned 082 @NonNull 083 protected final JsonParser newJsonParser(@NonNull Reader reader) throws IOException { 084 return ObjectUtils.notNull(getJsonFactory().createParser(reader)); 085 } 086 087 @Override 088 protected INodeItem deserializeToNodeItemInternal(@NonNull Reader reader, @NonNull URI documentUri) 089 throws IOException { 090 INodeItem retval; 091 try (JsonParser jsonParser = newJsonParser(reader)) { 092 MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser); 093 IBoundDefinitionModelAssembly definition = getDefinition(); 094 IConfiguration<DeserializationFeature<?>> configuration = getConfiguration(); 095 096 if (definition.isRoot() 097 && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) { 098 // now parse the root property 099 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}