001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.databind.model.info; 007 008import gov.nist.secauto.metaschema.core.model.IBoundObject; 009import gov.nist.secauto.metaschema.core.model.IMetaschemaData; 010import gov.nist.secauto.metaschema.core.util.ObjectUtils; 011import gov.nist.secauto.metaschema.databind.io.BindingException; 012import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex; 013import gov.nist.secauto.metaschema.databind.model.IBoundProperty; 014 015import java.lang.reflect.Constructor; 016import java.lang.reflect.InvocationTargetException; 017import java.util.Map; 018import java.util.function.Supplier; 019 020import edu.umd.cs.findbugs.annotations.NonNull; 021import edu.umd.cs.findbugs.annotations.Nullable; 022 023public interface IFeatureComplexItemValueHandler extends IItemValueHandler<IBoundObject> { 024 /** 025 * Get the Metaschema definition representing the bound complex data. 026 * 027 * @return the definition 028 */ 029 @NonNull 030 IBoundDefinitionModelComplex getDefinition(); 031 032 // /** 033 // * Get the name of the JSON key, if a JSON key is configured. 034 // * 035 // * @return the name of the JSON key flag if configured, or {@code null} 036 // * otherwise 037 // */ 038 // @Nullable 039 // String getJsonKeyFlagName(); 040 041 /** 042 * Get the mapping of JSON property names to property bindings. 043 * 044 * @return the mapping 045 */ 046 // REFACTOR: move JSON-specific methods to a binding cache implementation 047 @NonNull 048 Map<String, IBoundProperty<?>> getJsonProperties(); 049 050 // REFACTOR: flatten implementations? 051 @Override 052 @NonNull 053 IBoundObject deepCopyItem( 054 @NonNull IBoundObject item, 055 @Nullable IBoundObject parentInstance) throws BindingException; 056 057 /** 058 * The class this binding is to. 059 * 060 * @return the bound class 061 */ 062 @NonNull 063 Class<? extends IBoundObject> getBoundClass(); 064 065 /** 066 * Gets a new instance of the bound class. 067 * 068 * @param <CLASS> 069 * the type of the bound class 070 * @param supplier 071 * the metaschema data generator used to capture parse information 072 * (i.e., location) 073 * @return a Java object for the class 074 * @throws RuntimeException 075 * if the instance cannot be created due to a binding error 076 */ 077 @SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes") 078 @NonNull 079 default <CLASS extends IBoundObject> CLASS newInstance(@Nullable Supplier<IMetaschemaData> supplier) { 080 Class<?> clazz = getBoundClass(); 081 try { 082 CLASS retval; 083 if (supplier != null) { 084 @SuppressWarnings("unchecked") 085 Constructor<CLASS> constructor 086 = (Constructor<CLASS>) clazz.getDeclaredConstructor(IMetaschemaData.class); 087 retval = constructor.newInstance(supplier.get()); 088 } else { 089 @SuppressWarnings("unchecked") 090 Constructor<CLASS> constructor 091 = (Constructor<CLASS>) clazz.getDeclaredConstructor(); 092 retval = constructor.newInstance(); 093 } 094 return ObjectUtils.notNull(retval); 095 } catch (NoSuchMethodException ex) { 096 String msg = String.format("Class '%s' does not have a required no-arg constructor.", clazz.getName()); 097 throw new RuntimeException(msg, ex); 098 } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { 099 throw new RuntimeException(ex); 100 } 101 } 102 103 void callBeforeDeserialize( 104 @NonNull IBoundObject targetObject, 105 @Nullable IBoundObject parentObject) throws BindingException; 106 107 void callAfterDeserialize( 108 @NonNull IBoundObject targetObject, 109 @Nullable IBoundObject parentObject) throws BindingException; 110}