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") Constructor<CLASS> constructor
85              = (Constructor<CLASS>) clazz.getDeclaredConstructor(IMetaschemaData.class);
86          retval = constructor.newInstance(supplier.get());
87        } else {
88          @SuppressWarnings("unchecked") Constructor<CLASS> constructor
89              = (Constructor<CLASS>) clazz.getDeclaredConstructor();
90          retval = constructor.newInstance();
91        }
92        return ObjectUtils.notNull(retval);
93      } catch (NoSuchMethodException ex) {
94        String msg = String.format("Class '%s' does not have a required no-arg constructor.", clazz.getName());
95        throw new RuntimeException(msg, ex);
96      } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
97        throw new RuntimeException(ex);
98      }
99    }
100 
101   void callBeforeDeserialize(
102       @NonNull IBoundObject targetObject,
103       @Nullable IBoundObject parentObject) throws BindingException;
104 
105   void callAfterDeserialize(
106       @NonNull IBoundObject targetObject,
107       @Nullable IBoundObject parentObject) throws BindingException;
108 }