1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.model.impl;
7   
8   import java.util.Arrays;
9   import java.util.LinkedHashMap;
10  import java.util.Map;
11  import java.util.Set;
12  import java.util.function.Predicate;
13  import java.util.stream.Collectors;
14  
15  import dev.metaschema.core.datatype.markup.MarkupLine;
16  import dev.metaschema.core.datatype.markup.MarkupMultiline;
17  import dev.metaschema.core.model.AbstractFieldInstance;
18  import dev.metaschema.core.model.IAttributable;
19  import dev.metaschema.core.model.IBoundObject;
20  import dev.metaschema.core.util.CollectionUtil;
21  import dev.metaschema.core.util.ObjectUtils;
22  import dev.metaschema.databind.model.IBoundDefinitionModelAssembly;
23  import dev.metaschema.databind.model.IBoundDefinitionModelFieldComplex;
24  import dev.metaschema.databind.model.IBoundInstanceFlag;
25  import dev.metaschema.databind.model.IBoundInstanceModelChoiceGroup;
26  import dev.metaschema.databind.model.IBoundInstanceModelGroupedField;
27  import dev.metaschema.databind.model.IBoundProperty;
28  import dev.metaschema.databind.model.annotations.BoundGroupedField;
29  import dev.metaschema.databind.model.annotations.ModelUtil;
30  import edu.umd.cs.findbugs.annotations.NonNull;
31  import nl.talsmasoftware.lazy4j.Lazy;
32  
33  /**
34   * Represents an field model instance that is a member of a choice group
35   * instance.
36   */
37  /**
38   * Implementation of a complex field instance within a choice group.
39   * <p>
40   * This class represents a complex field that is a member of a choice group,
41   * allowing polymorphic model content.
42   */
43  public class InstanceModelGroupedFieldComplex
44      extends AbstractFieldInstance<
45          IBoundInstanceModelChoiceGroup,
46          IBoundDefinitionModelFieldComplex,
47          IBoundInstanceModelGroupedField,
48          IBoundDefinitionModelAssembly>
49      implements IBoundInstanceModelGroupedField {
50    @NonNull
51    private final BoundGroupedField annotation;
52    @NonNull
53    private final DefinitionField definition;
54    @NonNull
55    private final Lazy<Map<String, IBoundProperty<?>>> jsonProperties;
56    @NonNull
57    private final Lazy<Map<IAttributable.Key, Set<String>>> properties;
58  
59    /**
60     * Construct a new field model instance instance that is a member of a choice
61     * group instance.
62     *
63     * @param annotation
64     *          the Java annotation the instance is bound to
65     * @param definition
66     *          the assembly definition this instance is bound to
67     * @param container
68     *          the choice group instance containing the instance
69     */
70    public InstanceModelGroupedFieldComplex(
71        @NonNull BoundGroupedField annotation,
72        @NonNull DefinitionField definition,
73        @NonNull IBoundInstanceModelChoiceGroup container) {
74      super(container);
75      this.annotation = annotation;
76      this.definition = definition;
77      this.jsonProperties = ObjectUtils.notNull(Lazy.of(() -> {
78        Predicate<IBoundInstanceFlag> flagFilter = null;
79        IBoundInstanceFlag jsonKey = getEffectiveJsonKey();
80        if (jsonKey != null) {
81          flagFilter = flag -> !jsonKey.equals(flag);
82        }
83  
84        IBoundInstanceFlag jsonValueKey = getDefinition().getJsonValueKeyFlagInstance();
85        if (jsonValueKey != null) {
86          Predicate<IBoundInstanceFlag> jsonValueKeyFilter = flag -> !flag.equals(jsonValueKey);
87          flagFilter = flagFilter == null ? jsonValueKeyFilter : flagFilter.and(jsonValueKeyFilter);
88        }
89        return getDefinition().getJsonProperties(flagFilter);
90      }));
91      this.properties = ObjectUtils.notNull(
92          Lazy.of(() -> CollectionUtil.unmodifiableMap(ObjectUtils.notNull(
93              Arrays.stream(annotation.properties())
94                  .map(ModelUtil::toPropertyEntry)
95                  .collect(
96                      Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new))))));
97    }
98  
99    private BoundGroupedField getAnnotation() {
100     return annotation;
101   }
102 
103   // ------------------------------------------
104   // - Start annotation driven code - CPD-OFF -
105   // ------------------------------------------
106 
107   @Override
108   public Class<? extends IBoundObject> getBoundClass() {
109     return getAnnotation().binding();
110   }
111 
112   @Override
113   public Map<String, IBoundProperty<?>> getJsonProperties() {
114     return ObjectUtils.notNull(jsonProperties.get());
115   }
116 
117   @Override
118   public DefinitionField getDefinition() {
119     return definition;
120   }
121 
122   @Override
123   public String getFormalName() {
124     return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
125   }
126 
127   @Override
128   public MarkupLine getDescription() {
129     return ModelUtil.resolveToMarkupLine(getAnnotation().description());
130   }
131 
132   @Override
133   public Map<Key, Set<String>> getProperties() {
134     return ObjectUtils.notNull(properties.get());
135   }
136 
137   @Override
138   public MarkupMultiline getRemarks() {
139     return ModelUtil.resolveToMarkupMultiline(getAnnotation().remarks());
140   }
141 
142   @Override
143   public String getDiscriminatorValue() {
144     return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
145   }
146 
147   @Override
148   public String getUseName() {
149     return ModelUtil.resolveNoneOrValue(getAnnotation().useName());
150   }
151 
152   @Override
153   public Integer getUseIndex() {
154     return ModelUtil.resolveDefaultInteger(getAnnotation().useIndex());
155   }
156 
157   // ----------------------------------------
158   // - End annotation driven code - CPD-OFF -
159   // ----------------------------------------
160 }