001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.databind.model; 028 029import gov.nist.secauto.metaschema.core.model.INamedInstance; 030import gov.nist.secauto.metaschema.core.util.ObjectUtils; 031import gov.nist.secauto.metaschema.databind.io.BindingException; 032 033import java.lang.reflect.Field; 034import java.lang.reflect.ParameterizedType; 035import java.lang.reflect.Type; 036import java.util.Map; 037import java.util.Set; 038 039import javax.xml.namespace.QName; 040 041import edu.umd.cs.findbugs.annotations.NonNull; 042import edu.umd.cs.findbugs.annotations.Nullable; 043 044public interface IBoundNamedInstance extends INamedInstance { 045 046 @Override 047 default String getName() { 048 // delegate to the definition 049 return getDefinition().getName(); 050 } 051 052 @Override 053 default @NonNull Map<QName, Set<String>> getProperties() { 054 // TODO: implement 055 throw new UnsupportedOperationException(); 056 } 057 058 /** 059 * Get the {@link IClassBinding} for the Java class within which this property 060 * exists. 061 * 062 * @return the containing class's binding 063 */ 064 @NonNull 065 IClassBinding getParentClassBinding(); 066 067 /** 068 * Gets the bound Java field associated with this property. 069 * 070 * @return the Java field 071 */ 072 @NonNull 073 Field getField(); 074 075 @NonNull 076 default String getJavaFieldName() { 077 return ObjectUtils.notNull(getField().getName()); 078 } 079 080 /** 081 * Get the actual Java type of the underlying bound object. 082 * <p> 083 * This may be the same as the what is returned by {@link #getItemType()}, or 084 * may be a Java collection class. 085 * 086 * @return the raw type of the bound object 087 */ 088 @SuppressWarnings("null") 089 @NonNull 090 default Type getType() { 091 return getField().getGenericType(); 092 } 093 094 /** 095 * Get the item type of the bound object. An item type is the primitive or 096 * specialized type that represents that data associated with this binding. 097 * 098 * @return the item type of the bound object 099 */ 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}