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