1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.databind.model.info;
7   
8   import gov.nist.secauto.metaschema.core.model.IBoundObject;
9   import gov.nist.secauto.metaschema.core.model.IMetaschemaData;
10  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
11  import gov.nist.secauto.metaschema.databind.io.BindingException;
12  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
13  import gov.nist.secauto.metaschema.databind.model.IBoundProperty;
14  
15  import java.lang.reflect.Constructor;
16  import java.lang.reflect.InvocationTargetException;
17  import java.util.Map;
18  import java.util.function.Supplier;
19  
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  import edu.umd.cs.findbugs.annotations.Nullable;
22  
23  public interface IFeatureComplexItemValueHandler extends IItemValueHandler<IBoundObject> {
24    /**
25     * Get the Metaschema definition representing the bound complex data.
26     *
27     * @return the definition
28     */
29    @NonNull
30    IBoundDefinitionModelComplex getDefinition();
31  
32    // /**
33    // * Get the name of the JSON key, if a JSON key is configured.
34    // *
35    // * @return the name of the JSON key flag if configured, or {@code null}
36    // * otherwise
37    // */
38    // @Nullable
39    // String getJsonKeyFlagName();
40  
41    /**
42     * Get the mapping of JSON property names to property bindings.
43     *
44     * @return the mapping
45     */
46    // REFACTOR: move JSON-specific methods to a binding cache implementation
47    @NonNull
48    Map<String, IBoundProperty<?>> getJsonProperties();
49  
50    // REFACTOR: flatten implementations?
51    @Override
52    @NonNull
53    IBoundObject deepCopyItem(
54        @NonNull IBoundObject item,
55        @Nullable IBoundObject parentInstance) throws BindingException;
56  
57    /**
58     * The class this binding is to.
59     *
60     * @return the bound class
61     */
62    @NonNull
63    Class<? extends IBoundObject> getBoundClass();
64  
65    /**
66     * Gets a new instance of the bound class.
67     *
68     * @param <CLASS>
69     *          the type of the bound class
70     * @param supplier
71     *          the metaschema data generator used to capture parse information
72     *          (i.e., location)
73     * @return a Java object for the class
74     * @throws RuntimeException
75     *           if the instance cannot be created due to a binding error
76     */
77    @SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes")
78    @NonNull
79    default <CLASS extends IBoundObject> CLASS newInstance(@Nullable Supplier<IMetaschemaData> supplier) {
80      Class<?> clazz = getBoundClass();
81      try {
82        CLASS retval;
83        if (supplier != null) {
84          @SuppressWarnings("unchecked")
85          Constructor<CLASS> constructor
86              = (Constructor<CLASS>) clazz.getDeclaredConstructor(IMetaschemaData.class);
87          retval = constructor.newInstance(supplier.get());
88        } else {
89          @SuppressWarnings("unchecked")
90          Constructor<CLASS> constructor
91              = (Constructor<CLASS>) clazz.getDeclaredConstructor();
92          retval = constructor.newInstance();
93        }
94        return ObjectUtils.notNull(retval);
95      } catch (NoSuchMethodException ex) {
96        String msg = String.format("Class '%s' does not have a required no-arg constructor.", clazz.getName());
97        throw new RuntimeException(msg, ex);
98      } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
99        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 }