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.configuration.IMutableConfiguration; 013import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; 014import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory; 015import gov.nist.secauto.metaschema.core.model.IBoundObject; 016import gov.nist.secauto.metaschema.core.util.ObjectUtils; 017import gov.nist.secauto.metaschema.databind.io.AbstractDeserializer; 018import gov.nist.secauto.metaschema.databind.io.DeserializationFeature; 019import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly; 020 021import java.io.IOException; 022import java.io.Reader; 023import java.net.URI; 024 025import edu.umd.cs.findbugs.annotations.NonNull; 026import nl.talsmasoftware.lazy4j.Lazy; 027 028public class DefaultJsonDeserializer<CLASS extends IBoundObject> 029 extends AbstractDeserializer<CLASS> { 030 private Lazy<JsonFactory> factory; 031 032 /** 033 * Construct a new JSON deserializer that will parse the bound class identified 034 * by the {@code classBinding}. 035 * 036 * @param definition 037 * the bound class information for the Java type this deserializer is 038 * operating on 039 */ 040 public DefaultJsonDeserializer(@NonNull IBoundDefinitionModelAssembly definition) { 041 super(definition); 042 resetFactory(); 043 } 044 045 protected final void resetFactory() { 046 this.factory = Lazy.lazy(this::newFactoryInstance); 047 } 048 049 @Override 050 protected void configurationChanged(IMutableConfiguration<DeserializationFeature<?>> config) { 051 super.configurationChanged(config); 052 resetFactory(); 053 } 054 055 /** 056 * Get a JSON factory instance. 057 * <p> 058 * This method can be used by sub-classes to create a customized factory 059 * instance. 060 * 061 * @return the factory 062 */ 063 @NonNull 064 protected JsonFactory newFactoryInstance() { 065 return JsonFactoryFactory.instance(); 066 } 067 068 /** 069 * Get the parser factory associated with this deserializer. 070 * 071 * @return the factory instance 072 */ 073 @NonNull 074 protected JsonFactory getJsonFactory() { 075 return ObjectUtils.notNull(factory.get()); 076 } 077 078 /** 079 * Using the managed JSON factory, create a new JSON parser instance using the 080 * provided reader. 081 * 082 * @param reader 083 * the reader for the parser to read data from 084 * @return the new parser 085 * @throws IOException 086 * if an error occurred while creating the parser 087 */ 088 @SuppressWarnings("resource") // reader resource not owned 089 @NonNull 090 protected final JsonParser newJsonParser(@NonNull Reader reader) throws IOException { 091 return ObjectUtils.notNull(getJsonFactory().createParser(reader)); 092 } 093 094 @Override 095 protected INodeItem deserializeToNodeItemInternal(@NonNull Reader reader, @NonNull URI documentUri) 096 throws IOException { 097 INodeItem retval; 098 try (JsonParser jsonParser = newJsonParser(reader)) { 099 MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser); 100 IBoundDefinitionModelAssembly definition = getDefinition(); 101 IConfiguration<DeserializationFeature<?>> configuration = getConfiguration(); 102 103 if (definition.isRoot() 104 && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) { 105 // now parse the root property 106 CLASS value = ObjectUtils.requireNonNull(parser.readObjectRoot( 107 definition, 108 ObjectUtils.notNull(definition.getRootJsonName()))); 109 110 retval = INodeItemFactory.instance().newDocumentNodeItem(definition, documentUri, value); 111 } else { 112 // read the top-level definition 113 CLASS value = ObjectUtils.asType(parser.readObject(definition)); 114 115 retval = INodeItemFactory.instance().newAssemblyNodeItem(definition, documentUri, value); 116 } 117 return retval; 118 } 119 } 120 121 @Override 122 public CLASS deserializeToValueInternal(@NonNull Reader reader, @NonNull URI documentUri) throws IOException { 123 try (JsonParser jsonParser = newJsonParser(reader)) { 124 MetaschemaJsonReader parser = new MetaschemaJsonReader(jsonParser); 125 IBoundDefinitionModelAssembly definition = getDefinition(); 126 IConfiguration<DeserializationFeature<?>> configuration = getConfiguration(); 127 128 CLASS retval; 129 if (definition.isRoot() 130 && configuration.isFeatureEnabled(DeserializationFeature.DESERIALIZE_JSON_ROOT_PROPERTY)) { 131 132 // now parse the root property 133 retval = ObjectUtils.requireNonNull(parser.readObjectRoot( 134 definition, 135 ObjectUtils.notNull(definition.getRootJsonName()))); 136 } else { 137 // read the top-level definition 138 retval = ObjectUtils.asType(ObjectUtils.requireNonNull( 139 parser.readObject(definition))); 140 } 141 return retval; 142 } 143 } 144}