001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.databind.model;
007
008import java.lang.reflect.Field;
009import java.lang.reflect.Type;
010
011import edu.umd.cs.findbugs.annotations.NonNull;
012
013@FunctionalInterface
014public interface IFeatureJavaField extends IValuedMutable {
015
016  /**
017   * Gets the bound Java field associated with this instance.
018   *
019   * @return the Java field
020   */
021  @NonNull
022  Field getField();
023
024  /**
025   * Get the actual Java type of the underlying bound object.
026   * <p>
027   * This may be the same as the what is returned by {@link #getItemType()}, or
028   * may be a Java collection class.
029   *
030   * @return the raw type of the bound object
031   */
032  @SuppressWarnings("null")
033  @NonNull
034  default Type getType() {
035    return getField().getGenericType();
036  }
037
038  /**
039   * Get the item type of the bound object. An item type is the primitive or
040   * specialized type that represents that data associated with this binding.
041   *
042   * @return the item type of the bound object
043   */
044  @NonNull
045  default Class<?> getItemType() {
046    return (Class<?>) getType();
047  }
048
049  @Override
050  default Object getValue(@NonNull Object parent) {
051    Field field = getField();
052    // boolean accessable = field.canAccess(parent);
053    // field.setAccessible(true); // NOPMD - intentional
054    Object retval;
055    try {
056      Object result = field.get(parent);
057      retval = result;
058    } catch (IllegalArgumentException | IllegalAccessException ex) {
059      throw new IllegalArgumentException(
060          String.format("Unable to get the value of field '%s' in class '%s'.", field.getName(),
061              field.getDeclaringClass().getName()),
062          ex);
063      // } finally {
064      // field.setAccessible(accessable); // NOPMD - intentional
065    }
066    return retval;
067  }
068
069  @Override
070  default void setValue(@NonNull Object parentObject, Object value) {
071    Field field = getField();
072    // boolean accessable = field.canAccess(parentObject);
073    // field.setAccessible(true); // NOPMD - intentional
074    try {
075      field.set(parentObject, value);
076    } catch (IllegalArgumentException | IllegalAccessException ex) {
077      throw new IllegalArgumentException(
078          String.format(
079              "Unable to set the value of field '%s' in class '%s'." +
080                  " Perhaps this is a data type adapter problem on the declared class?",
081              field.getName(),
082              field.getDeclaringClass().getName()),
083          ex);
084      // } finally {
085      // field.setAccessible(accessable); // NOPMD - intentional
086    }
087  }
088
089}