1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.model.impl;
7
8 import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
9 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
10 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
11 import gov.nist.secauto.metaschema.core.model.AbstractInlineFieldDefinition;
12 import gov.nist.secauto.metaschema.core.model.IModule;
13 import gov.nist.secauto.metaschema.core.model.constraint.ISource;
14 import gov.nist.secauto.metaschema.core.model.constraint.IValueConstrained;
15 import gov.nist.secauto.metaschema.core.model.constraint.ValueConstraintSet;
16 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
17 import gov.nist.secauto.metaschema.databind.IBindingContext;
18 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
19 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelField;
20 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceFlag;
21 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelFieldScalar;
22 import gov.nist.secauto.metaschema.databind.model.IBoundModule;
23 import gov.nist.secauto.metaschema.databind.model.IGroupAs;
24 import gov.nist.secauto.metaschema.databind.model.annotations.BoundField;
25 import gov.nist.secauto.metaschema.databind.model.annotations.GroupAs;
26 import gov.nist.secauto.metaschema.databind.model.annotations.ModelUtil;
27 import gov.nist.secauto.metaschema.databind.model.annotations.ValueConstraints;
28 import gov.nist.secauto.metaschema.databind.model.info.IModelInstanceCollectionInfo;
29
30 import java.lang.reflect.Field;
31 import java.util.Optional;
32
33 import edu.umd.cs.findbugs.annotations.NonNull;
34 import edu.umd.cs.findbugs.annotations.Nullable;
35 import nl.talsmasoftware.lazy4j.Lazy;
36
37 public final class InstanceModelFieldScalar
38 extends AbstractInlineFieldDefinition<
39 IBoundDefinitionModelAssembly,
40 IBoundDefinitionModelField<Object>,
41 IBoundInstanceModelFieldScalar,
42 IBoundDefinitionModelAssembly,
43 IBoundInstanceFlag>
44 implements IBoundInstanceModelFieldScalar, IFeatureInstanceModelGroupAs<Object> {
45 @NonNull
46 private final Field javaField;
47 @NonNull
48 private final BoundField annotation;
49 @NonNull
50 private final Lazy<IModelInstanceCollectionInfo<Object>> collectionInfo;
51 @NonNull
52 private final IGroupAs groupAs;
53 @NonNull
54 private final IDataTypeAdapter<?> javaTypeAdapter;
55 @Nullable
56 private final Object defaultValue;
57 @NonNull
58 private final Lazy<IValueConstrained> constraints;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 @NonNull
74 public static InstanceModelFieldScalar newInstance(
75 @NonNull Field javaField,
76 @NonNull IBoundDefinitionModelAssembly containingDefinition) {
77 BoundField annotation = ModelUtil.getAnnotation(javaField, BoundField.class);
78 IGroupAs groupAs = ModelUtil.resolveDefaultGroupAs(
79 annotation.groupAs(),
80 containingDefinition.getContainingModule());
81
82 if (annotation.maxOccurs() == -1 || annotation.maxOccurs() > 1) {
83 if (IGroupAs.SINGLETON_GROUP_AS.equals(groupAs)) {
84 throw new IllegalStateException(String.format("Field '%s' on class '%s' is missing the '%s' annotation.",
85 javaField.getName(),
86 javaField.getDeclaringClass().getName(),
87 GroupAs.class.getName()));
88 }
89 } else if (!IGroupAs.SINGLETON_GROUP_AS.equals(groupAs)) {
90
91 throw new IllegalStateException(
92 String.format(
93 "Field '%s' on class '%s' has the '%s' annotation, but maxOccurs=1. A groupAs must not be specfied.",
94 javaField.getName(),
95 javaField.getDeclaringClass().getName(),
96 GroupAs.class.getName()));
97 }
98
99 return new InstanceModelFieldScalar(
100 javaField,
101 annotation,
102 groupAs,
103 containingDefinition);
104 }
105
106 private InstanceModelFieldScalar(
107 @NonNull Field javaField,
108 @NonNull BoundField annotation,
109 @NonNull IGroupAs groupAs,
110 @NonNull IBoundDefinitionModelAssembly containingDefinition) {
111 super(containingDefinition);
112 this.javaField = javaField;
113 this.annotation = annotation;
114 this.collectionInfo = ObjectUtils.notNull(Lazy.lazy(() -> IModelInstanceCollectionInfo.of(this)));
115 this.groupAs = groupAs;
116 this.javaTypeAdapter = ModelUtil.getDataTypeAdapter(
117 annotation.typeAdapter(),
118 containingDefinition.getBindingContext());
119 this.defaultValue = ModelUtil.resolveDefaultValue(annotation.defaultValue(), this.javaTypeAdapter);
120
121 IModule module = getContainingModule();
122
123 this.constraints = ObjectUtils.notNull(Lazy.lazy(() -> {
124 IValueConstrained retval = new ValueConstraintSet();
125 ValueConstraints valueAnnotation = annotation.valueConstraints();
126 ConstraintSupport.parse(valueAnnotation, ISource.modelSource(module), retval);
127 return retval;
128 }));
129 }
130
131
132
133
134
135 @Override
136 public IBindingContext getBindingContext() {
137 return getContainingDefinition().getBindingContext();
138 }
139
140 @Override
141 public IBoundModule getContainingModule() {
142 return getContainingDefinition().getContainingModule();
143 }
144
145 @Override
146 public Field getField() {
147 return javaField;
148 }
149
150
151
152
153
154
155 @NonNull
156 public BoundField getAnnotation() {
157 return annotation;
158 }
159
160 @SuppressWarnings("null")
161 @Override
162 public IModelInstanceCollectionInfo<Object> getCollectionInfo() {
163 return collectionInfo.get();
164 }
165
166 @SuppressWarnings("null")
167 @Override
168 @NonNull
169 public IValueConstrained getConstraintSupport() {
170 return constraints.get();
171 }
172
173 @Override
174 public IDataTypeAdapter<?> getJavaTypeAdapter() {
175 return javaTypeAdapter;
176 }
177
178 @Override
179 public Object getDefaultValue() {
180 return defaultValue;
181 }
182
183 @Override
184 public IGroupAs getGroupAs() {
185 return groupAs;
186 }
187
188 @Override
189 public String getFormalName() {
190 return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
191 }
192
193 @Override
194 public MarkupLine getDescription() {
195 return ModelUtil.resolveToMarkupLine(getAnnotation().description());
196 }
197
198 @Override
199 public Integer getUseIndex() {
200 int value = getAnnotation().useIndex();
201 return value == Integer.MIN_VALUE ? null : value;
202 }
203
204 @Override
205 public boolean isInXmlWrapped() {
206 return getAnnotation().inXmlWrapped();
207 }
208
209 @Override
210 public int getMinOccurs() {
211 return getAnnotation().minOccurs();
212 }
213
214 @Override
215 public int getMaxOccurs() {
216 return getAnnotation().maxOccurs();
217 }
218
219 @Override
220 public MarkupMultiline getRemarks() {
221 return ModelUtil.resolveToMarkupMultiline(getAnnotation().remarks());
222 }
223
224 @Override
225 public String getName() {
226
227
228 return ObjectUtils.notNull(
229 Optional.ofNullable(ModelUtil.resolveNoneOrValue(getAnnotation().useName())).orElse(getField().getName()));
230 }
231
232
233
234
235 }