001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.databind.model; 007 008import gov.nist.secauto.metaschema.core.model.IModelInstanceAbsolute; 009import gov.nist.secauto.metaschema.core.util.ObjectUtils; 010import gov.nist.secauto.metaschema.databind.model.info.IModelInstanceCollectionInfo; 011 012import java.lang.reflect.Field; 013import java.lang.reflect.ParameterizedType; 014import java.lang.reflect.Type; 015import java.util.Collection; 016import java.util.List; 017import java.util.Map; 018 019import edu.umd.cs.findbugs.annotations.NonNull; 020import edu.umd.cs.findbugs.annotations.Nullable; 021 022/** 023 * Represents an assembly or field instance bound to Java data. 024 * 025 * @param <ITEM> 026 * the Java type for associated bound objects 027 */ 028public interface IBoundInstanceModel<ITEM> 029 extends IBoundInstance<ITEM>, IModelInstanceAbsolute { 030 /** 031 * Get the collection Java item type for the Java field associated with this 032 * instance. 033 * 034 * @param field 035 * the Java field for the instance 036 * @return the Java item type 037 */ 038 @NonNull 039 static Class<?> getItemType(@NonNull Field field) { 040 Type fieldType = field.getGenericType(); 041 Class<?> rawType = ObjectUtils.notNull( 042 (Class<?>) (fieldType instanceof ParameterizedType ? ((ParameterizedType) fieldType).getRawType() : fieldType)); 043 044 Class<?> itemType; 045 if (Map.class.isAssignableFrom(rawType)) { 046 // this is a Map so the second generic type is the value 047 itemType = ObjectUtils.notNull((Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[1]); 048 } else if (List.class.isAssignableFrom(rawType)) { 049 // this is a List so there is only a single generic type 050 itemType = ObjectUtils.notNull((Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[0]); 051 } else { 052 // non-collection 053 itemType = rawType; 054 } 055 return itemType; 056 } 057 058 /** 059 * Get the collection Java item type for the Java field associated with this 060 * instance. 061 * 062 * @param <TYPE> 063 * the item's expected Java type 064 * @param field 065 * the Java field for the instance 066 * @param expectedItemType 067 * the item's expected Java type, which may be a super type of the 068 * item's type 069 * @return the Java item type 070 */ 071 @NonNull 072 static <TYPE> Class<? extends TYPE> getItemType(@NonNull Field field, @NonNull Class<TYPE> expectedItemType) { 073 Type fieldType = field.getGenericType(); 074 Class<?> rawType = ObjectUtils.notNull( 075 (Class<?>) (fieldType instanceof ParameterizedType ? ((ParameterizedType) fieldType).getRawType() : fieldType)); 076 077 Class<?> itemType; 078 if (Map.class.isAssignableFrom(rawType)) { 079 // this is a Map so the second generic type is the value 080 itemType = ObjectUtils.notNull((Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[1]); 081 } else if (List.class.isAssignableFrom(rawType)) { 082 // this is a List so there is only a single generic type 083 itemType = ObjectUtils.notNull((Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[0]); 084 } else { 085 // non-collection 086 itemType = rawType; 087 } 088 return ObjectUtils.notNull(itemType.asSubclass(expectedItemType)); 089 } 090 091 @Override 092 @NonNull 093 IBoundDefinitionModelAssembly getContainingDefinition(); 094 095 @Override 096 default Object getResolvedDefaultValue() { 097 return getMaxOccurs() == 1 ? getEffectiveDefaultValue() : getCollectionInfo().emptyValue(); 098 } 099 100 /** 101 * Get the item values associated with the provided value. 102 * 103 * @param value 104 * the value which may be a singleton or a collection 105 * @return the ordered collection of values 106 */ 107 @Override 108 @NonNull 109 default Collection<? extends Object> getItemValues(Object value) { 110 return getCollectionInfo().getItemsFromValue(value); 111 } 112 113 /** 114 * Get the Java binding information for the collection type supported by this 115 * instance. 116 * 117 * @return the collection Java binding information 118 */ 119 @NonNull 120 IModelInstanceCollectionInfo<ITEM> getCollectionInfo(); 121 122 /** 123 * Get the JSON key flag for the provided item. 124 * 125 * @param item 126 * the item to get the JSON key flag for 127 * @return the JSON key flag 128 */ 129 @Nullable 130 IBoundInstanceFlag getItemJsonKey(@NonNull Object item); 131}