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