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.datatype.IDataTypeAdapter; 009import gov.nist.secauto.metaschema.core.model.IBoundObject; 010import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; 011import gov.nist.secauto.metaschema.core.util.ObjectUtils; 012import gov.nist.secauto.metaschema.databind.model.info.IItemReadHandler; 013import gov.nist.secauto.metaschema.databind.model.info.IItemWriteHandler; 014 015import java.io.IOException; 016import java.util.Collection; 017import java.util.Map; 018import java.util.function.Function; 019import java.util.function.Predicate; 020import java.util.stream.Collectors; 021import java.util.stream.Stream; 022 023import edu.umd.cs.findbugs.annotations.NonNull; 024import edu.umd.cs.findbugs.annotations.Nullable; 025 026/** 027 * Represents a field definition bound to a Java class. 028 * <p> 029 * This definition is considered "complex", since it is bound to a Java class. 030 */ 031public interface IBoundDefinitionModelFieldComplex 032 extends IBoundDefinitionModelField<IBoundObject>, IBoundDefinitionModelComplex { 033 034 // Complex Field Definition Features 035 // ================================= 036 037 @Override 038 @NonNull 039 default IBoundDefinitionModelFieldComplex getDefinition() { 040 return this; 041 } 042 043 @Override 044 default Object getDefaultValue() { 045 Object retval = null; 046 IBoundDefinitionModelFieldComplex definition = getDefinition(); 047 IBoundFieldValue fieldValue = definition.getFieldValue(); 048 049 Object fieldValueDefault = fieldValue.getDefaultValue(); 050 if (fieldValueDefault != null) { 051 retval = definition.newInstance(null); 052 fieldValue.setValue(retval, fieldValueDefault); 053 054 // since the field value is non-null, populate the flags 055 for (IBoundInstanceFlag flag : definition.getFlagInstances()) { 056 Object flagDefault = flag.getResolvedDefaultValue(); 057 if (flagDefault != null) { 058 flag.setValue(retval, flagDefault); 059 } 060 } 061 } 062 return retval; 063 } 064 065 /** 066 * Get the bound field value associated with this field. 067 * 068 * @return the field's value binding 069 */ 070 @NonNull 071 IBoundFieldValue getFieldValue(); 072 073 @Override 074 @NonNull 075 default Object getFieldValue(@NonNull Object item) { 076 return ObjectUtils.requireNonNull(getFieldValue().getValue(item)); 077 } 078 079 @Override 080 @NonNull 081 default String getJsonValueKeyName() { 082 return getFieldValue().getJsonValueKeyName(); 083 } 084 085 @Override 086 @NonNull 087 default IDataTypeAdapter<?> getJavaTypeAdapter() { 088 return getFieldValue().getJavaTypeAdapter(); 089 } 090 091 @SuppressWarnings("PMD.NullAssignment") 092 @Override 093 @NonNull 094 default Map<String, IBoundProperty<?>> getJsonProperties(@Nullable Predicate<IBoundInstanceFlag> flagFilter) { 095 Predicate<IBoundInstanceFlag> actualFlagFilter = flagFilter; 096 097 IBoundFieldValue fieldValue = getFieldValue(); 098 IBoundInstanceFlag jsonValueKey = getDefinition().getJsonValueKeyFlagInstance(); 099 if (jsonValueKey != null) { 100 Predicate<IBoundInstanceFlag> jsonValueKeyFilter = flag -> !flag.equals(jsonValueKey); 101 actualFlagFilter = actualFlagFilter == null ? jsonValueKeyFilter : actualFlagFilter.and(jsonValueKeyFilter); 102 // ensure the field value is omitted too! 103 fieldValue = null; 104 } 105 106 Stream<? extends IBoundInstanceFlag> flagStream = getFlagInstances().stream(); 107 if (actualFlagFilter != null) { 108 flagStream = flagStream.filter(actualFlagFilter); 109 } 110 111 if (fieldValue != null) { 112 // determine if we use the field value or not 113 Collection<? extends IBoundInstanceFlag> flagInstances = flagStream 114 .collect(Collectors.toList()); 115 116 if (flagInstances.isEmpty()) { 117 // no relevant flags, so this field should expect a scalar value 118 fieldValue = null; 119 } 120 flagStream = flagInstances.stream(); 121 } 122 123 Stream<? extends IBoundProperty<?>> resultStream = fieldValue == null 124 ? flagStream 125 : Stream.concat(flagStream, Stream.of(getFieldValue())); 126 127 return ObjectUtils.notNull(resultStream 128 .collect(Collectors.toUnmodifiableMap(IBoundProperty::getJsonName, Function.identity()))); 129 } 130 131 @Override 132 @NonNull 133 default IBoundObject readItem(IBoundObject parent, IItemReadHandler handler) throws IOException { 134 return handler.readItemField(parent, this); 135 } 136 137 @Override 138 default void writeItem(IBoundObject item, IItemWriteHandler handler) throws IOException { 139 handler.writeItemField(item, this); 140 } 141 142 @Override 143 default boolean canHandleXmlQName(IEnhancedQName qname) { 144 // not handled, since not root 145 return false; 146 } 147}