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 assert flag != null; 057 058 Object flagDefault = flag.getResolvedDefaultValue(); 059 if (flagDefault != null) { 060 flag.setValue(retval, flagDefault); 061 } 062 } 063 } 064 return retval; 065 } 066 067 /** 068 * Get the bound field value associated with this field. 069 * 070 * @return the field's value binding 071 */ 072 @NonNull 073 IBoundFieldValue getFieldValue(); 074 075 @Override 076 @NonNull 077 default Object getFieldValue(@NonNull Object item) { 078 return ObjectUtils.requireNonNull(getFieldValue().getValue(item)); 079 } 080 081 @Override 082 @NonNull 083 default String getJsonValueKeyName() { 084 return getFieldValue().getJsonValueKeyName(); 085 } 086 087 @Override 088 @NonNull 089 default IDataTypeAdapter<?> getJavaTypeAdapter() { 090 return getFieldValue().getJavaTypeAdapter(); 091 } 092 093 @SuppressWarnings("PMD.NullAssignment") 094 @Override 095 @NonNull 096 default Map<String, IBoundProperty<?>> getJsonProperties(@Nullable Predicate<IBoundInstanceFlag> flagFilter) { 097 Predicate<IBoundInstanceFlag> actualFlagFilter = flagFilter; 098 099 IBoundFieldValue fieldValue = getFieldValue(); 100 IBoundInstanceFlag jsonValueKey = getDefinition().getJsonValueKeyFlagInstance(); 101 if (jsonValueKey != null) { 102 Predicate<IBoundInstanceFlag> jsonValueKeyFilter = flag -> !flag.equals(jsonValueKey); 103 actualFlagFilter = actualFlagFilter == null ? jsonValueKeyFilter : actualFlagFilter.and(jsonValueKeyFilter); 104 // ensure the field value is omitted too! 105 fieldValue = null; 106 } 107 108 Stream<? extends IBoundInstanceFlag> flagStream = getFlagInstances().stream(); 109 if (actualFlagFilter != null) { 110 flagStream = flagStream.filter(actualFlagFilter); 111 } 112 113 if (fieldValue != null) { 114 // determine if we use the field value or not 115 Collection<? extends IBoundInstanceFlag> flagInstances = flagStream 116 .collect(Collectors.toList()); 117 118 if (flagInstances.isEmpty()) { 119 // no relevant flags, so this field should expect a scalar value 120 fieldValue = null; 121 } 122 flagStream = flagInstances.stream(); 123 } 124 125 Stream<? extends IBoundProperty<?>> resultStream = fieldValue == null 126 ? flagStream 127 : Stream.concat(flagStream, Stream.of(getFieldValue())); 128 129 return ObjectUtils.notNull(resultStream 130 .collect(Collectors.toUnmodifiableMap(IBoundProperty::getJsonName, Function.identity()))); 131 } 132 133 @Override 134 @NonNull 135 default IBoundObject readItem(IBoundObject parent, IItemReadHandler handler) throws IOException { 136 return handler.readItemField(parent, this); 137 } 138 139 @Override 140 default void writeItem(IBoundObject item, IItemWriteHandler handler) throws IOException { 141 handler.writeItemField(item, this); 142 } 143 144 @Override 145 default boolean canHandleXmlQName(IEnhancedQName qname) { 146 // not handled, since not root 147 return false; 148 } 149}