1
2
3
4
5
6 package dev.metaschema.databind.model.info;
7
8 import java.io.IOException;
9 import java.lang.reflect.Field;
10 import java.lang.reflect.ParameterizedType;
11 import java.lang.reflect.Type;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Map;
15
16 import dev.metaschema.core.model.IBoundObject;
17 import dev.metaschema.core.model.JsonGroupAsBehavior;
18 import dev.metaschema.databind.io.BindingException;
19 import dev.metaschema.databind.model.IBoundInstanceModel;
20 import edu.umd.cs.findbugs.annotations.NonNull;
21 import edu.umd.cs.findbugs.annotations.Nullable;
22
23
24
25
26
27
28
29
30
31
32
33 public interface IModelInstanceCollectionInfo<ITEM> {
34
35
36
37
38
39
40
41
42
43
44
45
46
47 @NonNull
48 static <T> IModelInstanceCollectionInfo<T> of(
49 @NonNull IBoundInstanceModel<T> instance) {
50
51
52 Type type = instance.getType();
53 Field field = instance.getField();
54
55 IModelInstanceCollectionInfo<T> retval;
56 if (instance.getMaxOccurs() == -1 || instance.getMaxOccurs() > 1) {
57
58 JsonGroupAsBehavior jsonGroupAs = instance.getJsonGroupAsBehavior();
59
60
61 if (!(type instanceof ParameterizedType)) {
62 switch (jsonGroupAs) {
63 case KEYED:
64 throw new IllegalStateException(
65 String.format("The field '%s' on class '%s' has data type of '%s'," + " but should have a type of '%s'.",
66 field.getName(),
67 field.getDeclaringClass().getName(),
68 field.getType().getName(), Map.class.getName()));
69 case LIST:
70 case SINGLETON_OR_LIST:
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(),
74 field.getDeclaringClass().getName(),
75 field.getType().getName(), List.class.getName()));
76 default:
77
78 throw new IllegalStateException(jsonGroupAs.name());
79 }
80 }
81
82 Class<?> rawType = (Class<?>) ((ParameterizedType) type).getRawType();
83 if (JsonGroupAsBehavior.KEYED.equals(jsonGroupAs)) {
84 if (!Map.class.isAssignableFrom(rawType)) {
85 throw new IllegalArgumentException(String.format(
86 "The field '%s' on class '%s' has data type '%s', which is not the expected '%s' derived data type.",
87 field.getName(),
88 field.getDeclaringClass().getName(),
89 field.getType().getName(),
90 Map.class.getName()));
91 }
92 retval = new MapCollectionInfo<>(instance);
93 } else {
94 if (!List.class.isAssignableFrom(rawType)) {
95 throw new IllegalArgumentException(String.format(
96 "The field '%s' on class '%s' has data type '%s', which is not the expected '%s' derived data type.",
97 field.getName(),
98 field.getDeclaringClass().getName(),
99 field.getType().getName(),
100 List.class.getName()));
101 }
102 retval = new ListCollectionInfo<>(instance);
103 }
104 } else {
105
106 if (type instanceof ParameterizedType) {
107 throw new IllegalStateException(String.format(
108 "The field '%s' on class '%s' has a data parmeterized type of '%s',"
109 + " but the occurance is not multi-valued.",
110 field.getName(),
111 field.getDeclaringClass().getName(),
112 field.getType().getName()));
113 }
114 retval = new SingletonCollectionInfo<>(instance);
115 }
116 return retval;
117 }
118
119
120
121
122
123
124 @NonNull
125 IBoundInstanceModel<ITEM> getInstance();
126
127
128
129
130
131
132
133
134 int size(@Nullable Object value);
135
136
137
138
139
140
141
142
143
144 boolean isEmpty(@Nullable Object value);
145
146
147
148
149
150
151 @NonNull
152 Class<? extends ITEM> getItemType();
153
154
155
156
157
158
159
160
161 @NonNull
162 default Collection<? extends ITEM> getItemsFromParentInstance(@NonNull Object parentInstance) {
163 Object value = getInstance().getValue(parentInstance);
164 return getItemsFromValue(value);
165 }
166
167
168
169
170
171
172
173
174 @NonNull
175 Collection<? extends ITEM> getItemsFromValue(Object value);
176
177
178
179
180
181
182 Object emptyValue();
183
184
185
186
187
188
189
190
191
192
193
194
195 Object deepCopyItems(@NonNull IBoundObject fromObject, @NonNull IBoundObject toObject) throws BindingException;
196
197
198
199
200
201
202
203
204
205
206
207
208
209 @Nullable
210 Object readItems(@NonNull IModelInstanceReadHandler<ITEM> handler) throws IOException;
211
212
213
214
215
216
217
218
219
220
221
222 void writeItems(
223 @NonNull IModelInstanceWriteHandler<ITEM> handler,
224 @NonNull Object value) throws IOException;
225 }