1 /* 2 * Portions of this software was developed by employees of the National Institute 3 * of Standards and Technology (NIST), an agency of the Federal Government and is 4 * being made available as a public service. Pursuant to title 17 United States 5 * Code Section 105, works of NIST employees are not subject to copyright 6 * protection in the United States. This software may be subject to foreign 7 * copyright. Permission in the United States and in foreign countries, to the 8 * extent that NIST may hold copyright, to use, copy, modify, create derivative 9 * works, and distribute this software and its documentation without fee is hereby 10 * granted on a non-exclusive basis, provided that this notice and disclaimer 11 * of warranty appears in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 14 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 15 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 17 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 18 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 19 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 20 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 21 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 22 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 23 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 24 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 25 */ 26 27 package gov.nist.secauto.metaschema.databind.model; 28 29 import gov.nist.secauto.metaschema.core.model.INamedInstance; 30 import gov.nist.secauto.metaschema.core.util.ObjectUtils; 31 import gov.nist.secauto.metaschema.databind.io.BindingException; 32 33 import java.lang.reflect.Field; 34 import java.lang.reflect.ParameterizedType; 35 import java.lang.reflect.Type; 36 import java.util.Map; 37 import java.util.Set; 38 39 import javax.xml.namespace.QName; 40 41 import edu.umd.cs.findbugs.annotations.NonNull; 42 import edu.umd.cs.findbugs.annotations.Nullable; 43 44 public interface IBoundNamedInstance extends INamedInstance { 45 46 @Override 47 default String getName() { 48 // delegate to the definition 49 return getDefinition().getName(); 50 } 51 52 @Override 53 default @NonNull Map<QName, Set<String>> getProperties() { 54 // TODO: implement 55 throw new UnsupportedOperationException(); 56 } 57 58 /** 59 * Get the {@link IClassBinding} for the Java class within which this property 60 * exists. 61 * 62 * @return the containing class's binding 63 */ 64 @NonNull 65 IClassBinding getParentClassBinding(); 66 67 /** 68 * Gets the bound Java field associated with this property. 69 * 70 * @return the Java field 71 */ 72 @NonNull 73 Field getField(); 74 75 @NonNull 76 default String getJavaFieldName() { 77 return ObjectUtils.notNull(getField().getName()); 78 } 79 80 /** 81 * Get the actual Java type of the underlying bound object. 82 * <p> 83 * This may be the same as the what is returned by {@link #getItemType()}, or 84 * may be a Java collection class. 85 * 86 * @return the raw type of the bound object 87 */ 88 @SuppressWarnings("null") 89 @NonNull 90 default Type getType() { 91 return getField().getGenericType(); 92 } 93 94 /** 95 * Get the item type of the bound object. An item type is the primitive or 96 * specialized type that represents that data associated with this binding. 97 * 98 * @return the item type of the bound object 99 */ 100 @NonNull 101 default Class<?> getItemType() { 102 return (Class<?>) getType(); 103 } 104 105 /** 106 * Get the current value from the provided {@code parentInstance} object. The 107 * provided object must be of the type associated with the definition containing 108 * this property. 109 * 110 * @param parentInstance 111 * the object associated with the definition containing this property 112 * @return the value if available, or {@code null} otherwise 113 */ 114 @Override 115 default Object getValue(@NonNull Object parentInstance) { 116 Field field = getField(); 117 boolean accessable = field.canAccess(parentInstance); 118 field.setAccessible(true); // NOPMD - intentional 119 Object retval; 120 try { 121 Object result = field.get(parentInstance); 122 retval = result; 123 } catch (IllegalArgumentException | IllegalAccessException ex) { 124 throw new IllegalArgumentException( 125 String.format("Unable to get the value of field '%s' in class '%s'.", field.getName(), 126 field.getDeclaringClass().getName()), 127 ex); 128 } finally { 129 field.setAccessible(accessable); // NOPMD - intentional 130 } 131 return retval; 132 } 133 134 /** 135 * Set the provided value on the provided object. The provided object must be of 136 * the item's type associated with this property. 137 * 138 * @param parentInstance 139 * the object 140 * @param value 141 * a value, which may be a simple {@link Type} or a 142 * {@link ParameterizedType} for a collection 143 */ 144 default void setValue(@NonNull Object parentInstance, Object value) { 145 Field field = getField(); 146 boolean accessable = field.canAccess(parentInstance); 147 field.setAccessible(true); // NOPMD - intentional 148 try { 149 field.set(parentInstance, value); 150 } catch (IllegalArgumentException | IllegalAccessException ex) { 151 throw new IllegalArgumentException( 152 String.format( 153 "Unable to set the value of field '%s' in class '%s'. Perhaps this is a data type adapter problem on the declared class?", 154 field.getName(), 155 field.getDeclaringClass().getName()), 156 ex); 157 } finally { 158 field.setAccessible(accessable); // NOPMD - intentional 159 } 160 } 161 162 @Nullable 163 Object defaultValue() throws BindingException; 164 165 /** 166 * Copy this instance from one parent object to another. 167 * 168 * @param fromInstance 169 * the object to copy from 170 * @param toInstance 171 * the object to copy to 172 * @throws BindingException 173 * if an error occurred while processing the object bindings 174 */ 175 void copyBoundObject(@NonNull Object fromInstance, @NonNull Object toInstance) throws BindingException; 176 }