1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.databind.model.info;
28
29 import gov.nist.secauto.metaschema.core.model.JsonGroupAsBehavior;
30 import gov.nist.secauto.metaschema.databind.io.BindingException;
31 import gov.nist.secauto.metaschema.databind.io.json.IJsonParsingContext;
32 import gov.nist.secauto.metaschema.databind.io.json.IJsonWritingContext;
33 import gov.nist.secauto.metaschema.databind.io.xml.IXmlParsingContext;
34 import gov.nist.secauto.metaschema.databind.io.xml.IXmlWritingContext;
35 import gov.nist.secauto.metaschema.databind.model.IBoundNamedModelInstance;
36
37 import java.io.IOException;
38 import java.lang.reflect.Field;
39 import java.lang.reflect.ParameterizedType;
40 import java.lang.reflect.Type;
41 import java.util.Collection;
42 import java.util.List;
43 import java.util.Map;
44
45 import javax.xml.namespace.QName;
46 import javax.xml.stream.XMLStreamException;
47 import javax.xml.stream.events.StartElement;
48
49 import edu.umd.cs.findbugs.annotations.NonNull;
50 import edu.umd.cs.findbugs.annotations.Nullable;
51
52
53 public interface IModelPropertyInfo {
54
55 @NonNull
56 static IModelPropertyInfo newPropertyInfo(
57 @NonNull IBoundNamedModelInstance instance) {
58
59 Type type = instance.getType();
60 Field field = instance.getField();
61
62 IModelPropertyInfo retval;
63 if (instance.getMaxOccurs() == -1 || instance.getMaxOccurs() > 1) {
64
65 JsonGroupAsBehavior jsonGroupAs = instance.getJsonGroupAsBehavior();
66
67
68 if (!(type instanceof ParameterizedType)) {
69 switch (jsonGroupAs) {
70 case KEYED:
71 throw new IllegalStateException(
72 String.format("The field '%s' on class '%s' has data type of '%s'," + " but should have a type of '%s'.",
73 field.getName(), instance.getParentClassBinding().getBoundClass().getName(),
74 field.getType().getName(), Map.class.getName()));
75 case LIST:
76 case SINGLETON_OR_LIST:
77 throw new IllegalStateException(
78 String.format("The field '%s' on class '%s' has data type of '%s'," + " but should have a type of '%s'.",
79 field.getName(), instance.getParentClassBinding().getBoundClass().getName(),
80 field.getType().getName(), List.class.getName()));
81 default:
82
83 throw new IllegalStateException(jsonGroupAs.name());
84 }
85 }
86
87 Class<?> rawType = (Class<?>) ((ParameterizedType) type).getRawType();
88 if (JsonGroupAsBehavior.KEYED.equals(jsonGroupAs)) {
89 if (!Map.class.isAssignableFrom(rawType)) {
90 throw new IllegalArgumentException(String.format(
91 "The field '%s' on class '%s' has data type '%s', which is not the expected '%s' derived data type.",
92 field.getName(),
93 instance.getParentClassBinding().getBoundClass().getName(),
94 field.getType().getName(),
95 Map.class.getName()));
96 }
97 retval = new MapPropertyInfo(instance);
98 } else {
99 if (!List.class.isAssignableFrom(rawType)) {
100 throw new IllegalArgumentException(String.format(
101 "The field '%s' on class '%s' has data type '%s', which is not the expected '%s' derived data type.",
102 field.getName(),
103 instance.getParentClassBinding().getBoundClass().getName(),
104 field.getType().getName(),
105 List.class.getName()));
106 }
107 retval = new ListPropertyInfo(instance);
108 }
109 } else {
110
111 if (type instanceof ParameterizedType) {
112 throw new IllegalStateException(String.format(
113 "The field '%s' on class '%s' has a data parmeterized type of '%s',"
114 + " but the occurance is not multi-valued.",
115 field.getName(),
116 instance.getParentClassBinding().getBoundClass().getName(),
117 field.getType().getName()));
118 }
119 retval = new SingletonPropertyInfo(instance);
120 }
121 return retval;
122 }
123
124
125
126
127
128
129 @NonNull
130 IBoundNamedModelInstance getProperty();
131
132 int getItemCount(@Nullable Object value);
133
134
135
136
137
138
139 @NonNull
140 Class<?> getItemType();
141
142 @NonNull
143 IPropertyCollector newPropertyCollector();
144
145 default boolean isJsonKeyRequired() {
146 return false;
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 void readValues(
166 @NonNull IPropertyCollector collector,
167 @NonNull Object parentInstance,
168 @NonNull IJsonParsingContext context)
169 throws IOException;
170
171 boolean readValues(
172 @NonNull IPropertyCollector collector,
173 @NonNull Object parentInstance,
174 @NonNull StartElement start,
175 @NonNull IXmlParsingContext context)
176 throws IOException, XMLStreamException;
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 void writeValues(@NonNull Object value, @NonNull QName parentName, @NonNull IXmlWritingContext context)
193 throws XMLStreamException, IOException;
194
195 void writeValues(@NonNull Object parentInstance, @NonNull IJsonWritingContext context) throws IOException;
196
197 boolean isValueSet(@NonNull Object parentInstance) throws IOException;
198
199 @NonNull
200 default Collection<? extends Object> getItemsFromParentInstance(@NonNull Object parentInstance) {
201 Object value = getProperty().getValue(parentInstance);
202 return getItemsFromValue(value);
203 }
204
205 @NonNull
206 Collection<? extends Object> getItemsFromValue(Object value);
207
208 void copy(@NonNull Object fromInstance, @NonNull Object toInstance, @NonNull IPropertyCollector collector)
209 throws BindingException;
210 }