1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.model;
7   
8   import java.lang.reflect.Field;
9   import java.lang.reflect.Type;
10  
11  import edu.umd.cs.findbugs.annotations.NonNull;
12  
13  /**
14   * Provides access to a Java field that is bound to a Metaschema instance.
15   */
16  @FunctionalInterface
17  public interface IFeatureJavaField extends IValuedMutable {
18  
19    /**
20     * Gets the bound Java field associated with this instance.
21     *
22     * @return the Java field
23     */
24    @NonNull
25    Field getField();
26  
27    /**
28     * Get the actual Java type of the underlying bound object.
29     * <p>
30     * This may be the same as the what is returned by {@link #getItemType()}, or
31     * may be a Java collection class.
32     *
33     * @return the raw type of the bound object
34     */
35    @SuppressWarnings("null")
36    @NonNull
37    default Type getType() {
38      return getField().getGenericType();
39    }
40  
41    /**
42     * Get the item type of the bound object. An item type is the primitive or
43     * specialized type that represents that data associated with this binding.
44     *
45     * @return the item type of the bound object
46     */
47    @NonNull
48    default Class<?> getItemType() {
49      return (Class<?>) getType();
50    }
51  
52    @Override
53    default Object getValue(@NonNull Object parent) {
54      Field field = getField();
55      // boolean accessable = field.canAccess(parent);
56      // field.setAccessible(true);
57      Object retval;
58      try {
59        Object result = field.get(parent);
60        retval = result;
61      } catch (IllegalArgumentException | IllegalAccessException ex) {
62        throw new IllegalArgumentException(
63            String.format("Unable to get the value of field '%s' in class '%s'.", field.getName(),
64                field.getDeclaringClass().getName()),
65            ex);
66        // } finally {
67        // field.setAccessible(accessable);
68      }
69      return retval;
70    }
71  
72    @Override
73    default void setValue(@NonNull Object parentObject, Object value) {
74      Field field = getField();
75      // boolean accessable = field.canAccess(parentObject);
76      // field.setAccessible(true);
77      try {
78        field.set(parentObject, value);
79      } catch (IllegalArgumentException | IllegalAccessException ex) {
80        throw new IllegalArgumentException(
81            String.format(
82                "Unable to set the value of field '%s' in class '%s'." +
83                    " Perhaps this is a data type adapter problem on the declared class?",
84                field.getName(),
85                field.getDeclaringClass().getName()),
86            ex);
87        // } finally {
88        // field.setAccessible(accessable);
89      }
90    }
91  
92  }