Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/util/json/JSONObject.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children | db918c531e6d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 | |
19 package gov.nasa.jpf.util.json; | |
20 | |
21 import gov.nasa.jpf.JPF; | |
22 import gov.nasa.jpf.JPFException; | |
23 import gov.nasa.jpf.util.JPFLogger; | |
24 import gov.nasa.jpf.util.ObjectConverter; | |
25 import gov.nasa.jpf.vm.ChoiceGenerator; | |
26 import gov.nasa.jpf.vm.ClassInfo; | |
27 import gov.nasa.jpf.vm.ClinitRequired; | |
28 import gov.nasa.jpf.vm.ElementInfo; | |
29 import gov.nasa.jpf.vm.FieldInfo; | |
30 import gov.nasa.jpf.vm.Fields; | |
31 import gov.nasa.jpf.vm.MJIEnv; | |
32 import gov.nasa.jpf.vm.ThreadInfo; | |
33 | |
34 import java.util.HashMap; | |
35 import java.util.Set; | |
36 | |
37 /** | |
38 * Object parsed from JSON document. | |
39 * @author Ivan Mushketik | |
40 */ | |
41 public class JSONObject{ | |
42 | |
43 private static final JPFLogger logger = JPF.getLogger("gov.nasa.jpf.util.json.JSONObject"); | |
44 | |
45 private HashMap<String, Value> keyValues = new HashMap<String, Value>(); | |
46 private HashMap<String, CGCall> cgCalls = new HashMap<String, CGCall>(); | |
47 | |
48 void addValue(String key, Value value) { | |
49 if (keyValues.containsKey(key)) { | |
50 throw new JPFException("Attempt to add two nodes with the same key in JSON object"); | |
51 } | |
52 | |
53 keyValues.put(key, value); | |
54 } | |
55 | |
56 /** | |
57 * Get value read from JSON document with specified key. | |
58 * @param key - value's key. | |
59 * @return read value. | |
60 */ | |
61 public Value getValue(String key) { | |
62 return keyValues.get(key); | |
63 } | |
64 | |
65 public String[] getValuesKeys() { | |
66 Set<String> valuesKeys = keyValues.keySet(); | |
67 String[] result = new String[keyValues.size()]; | |
68 | |
69 valuesKeys.toArray(result); | |
70 return result; | |
71 } | |
72 | |
73 public void addCGCall(String key, CGCall cgCall) { | |
74 if (cgCalls.containsKey(key)) { | |
75 throw new JPFException("Attempt to add two CG with the same key in JSON object"); | |
76 } | |
77 | |
78 cgCalls.put(key, cgCall); | |
79 } | |
80 | |
81 public CGCall getCGCall(String key) { | |
82 return cgCalls.get(key); | |
83 } | |
84 | |
85 public String[] getCGCallsKeys() { | |
86 Set<String> cgKeys = cgCalls.keySet(); | |
87 String[] result = new String[cgKeys.size()]; | |
88 | |
89 cgKeys.toArray(result); | |
90 return result; | |
91 } | |
92 | |
93 /** | |
94 * check if all required ClassInfos for this object have been initialized so | |
95 * that the caller can decide if it has to re-execute before proceeding | |
96 * | |
97 * NOTE - this currently does not support concrete field types that are subtypes | |
98 * of the respective field types | |
99 */ | |
100 public boolean requiresClinitExecution (ClassInfo ci, ThreadInfo ti){ | |
101 while (ci != null){ | |
102 if (ci.pushRequiredClinits(ti)){ | |
103 return true; | |
104 } | |
105 | |
106 for (FieldInfo fi : ci.getDeclaredInstanceFields()) { | |
107 ClassInfo ciField = fi.getTypeClassInfo(); | |
108 if (requiresClinitExecution(ciField, ti)){ | |
109 return true; | |
110 } | |
111 } | |
112 | |
113 ci = ci.getSuperClass(); | |
114 } | |
115 | |
116 return false; | |
117 } | |
118 | |
119 //--- the fillers | |
120 | |
121 // NOTE - (pcm) before calling this method you have to make sure all required | |
122 // types are initialized | |
123 | |
124 public int fillObject (MJIEnv env, ClassInfo ci, ChoiceGenerator<?>[] cgs, String prefix) throws ClinitRequired { | |
125 int newObjRef = env.newObject(ci); | |
126 ElementInfo ei = env.getHeap().getModifiable(newObjRef); | |
127 | |
128 // Fill all fields for this class until it has a super class | |
129 while (ci != null) { | |
130 FieldInfo[] fields = ci.getDeclaredInstanceFields(); | |
131 | |
132 for (FieldInfo fi : fields) { | |
133 String fieldName = fi.getName(); | |
134 Value val = getValue(fieldName); | |
135 CGCall cgCall = getCGCall(fieldName); | |
136 | |
137 // If a value was defined in JSON document | |
138 if (val != null) { | |
139 fillFromValue(fi, ei, val, env, cgs, prefix); | |
140 | |
141 } else if (cgCall != null) { | |
142 // Value of this field should be taken from CG | |
143 String cgId = prefix + fieldName; | |
144 ChoiceGenerator<?> cg = getCGByID(cgs, cgId); | |
145 assert cg != null : "Expected CG with id " + cgId; | |
146 | |
147 Object cgResult = cg.getNextChoice(); | |
148 | |
149 if (!fi.isReference()) { | |
150 convertPrimititve(ei, fi, cgResult); | |
151 } else { | |
152 int newFieldRef = ObjectConverter.JPFObjectFromJavaObject(env, cgResult); | |
153 ei.setReferenceField(fi, newFieldRef); | |
154 } | |
155 } else { | |
156 logger.warning("Value for field ", fi.getFullName(), " isn't specified"); | |
157 } | |
158 } | |
159 | |
160 ci = ci.getSuperClass(); | |
161 } | |
162 | |
163 return newObjRef; | |
164 } | |
165 | |
166 private void fillFromValue(FieldInfo fi, ElementInfo ei, Value val, MJIEnv env, ChoiceGenerator<?>[] cgs, String prefix) { | |
167 String fieldName = fi.getName(); | |
168 // Handle primitive types | |
169 if (!fi.isReference()) { | |
170 fillPrimitive(ei, fi, val); | |
171 | |
172 } else { | |
173 if (isArrayType(fi.getType())) { | |
174 int newArrRef = createArray(env, fi.getTypeClassInfo(), val, cgs, prefix + fieldName); | |
175 ei.setReferenceField(fi, newArrRef); | |
176 | |
177 } else { | |
178 Creator creator = CreatorsFactory.getCreator(fi.getType()); | |
179 if (creator != null) { | |
180 int newSubObjRef = creator.create(env, fi.getType(), val); | |
181 ei.setReferenceField(fi, newSubObjRef); | |
182 | |
183 } else { | |
184 // Not a special case. Fill it recursively | |
185 ClassInfo ciField = fi.getTypeClassInfo(); | |
186 if (ciField.pushRequiredClinits(env.getThreadInfo())){ | |
187 throw new ClinitRequired(ciField); | |
188 } | |
189 | |
190 JSONObject jsonObj = val.getObject(); | |
191 int fieldRef = MJIEnv.NULL; | |
192 if (jsonObj != null) { | |
193 fieldRef = jsonObj.fillObject(env, ciField, cgs, prefix + fieldName); | |
194 } | |
195 ei.setReferenceField(fi.getName(), fieldRef); | |
196 } | |
197 } | |
198 } | |
199 } | |
200 | |
201 | |
202 private static void fillPrimitive(ElementInfo ei, FieldInfo fi, Value val) { | |
203 String primitiveName = fi.getType(); | |
204 | |
205 if (primitiveName.equals("boolean")) { | |
206 ei.setBooleanField(fi, val.getBoolean()); | |
207 | |
208 } else if (primitiveName.equals("byte")) { | |
209 ei.setByteField(fi, val.getDouble().byteValue()); | |
210 | |
211 } else if (primitiveName.equals("short")) { | |
212 ei.setShortField(fi, val.getDouble().shortValue()); | |
213 | |
214 } else if (primitiveName.equals("int")) { | |
215 ei.setIntField(fi, val.getDouble().intValue()); | |
216 | |
217 } else if (primitiveName.equals("long")) { | |
218 ei.setLongField(fi, val.getDouble().longValue()); | |
219 | |
220 } else if (primitiveName.equals("float")) { | |
221 ei.setFloatField(fi, val.getDouble().floatValue()); | |
222 | |
223 } else if (primitiveName.equals("double")) { | |
224 ei.setDoubleField(fi, val.getDouble()); | |
225 } | |
226 } | |
227 | |
228 public int createArray(MJIEnv env, ClassInfo ciArray, Value value, ChoiceGenerator<?>[] cgs, String prefix) { | |
229 Value vals[] = value.getArray(); | |
230 | |
231 ClassInfo ciElement = ciArray.getComponentClassInfo(); | |
232 String arrayElementType = ciElement.getName(); | |
233 int arrayRef; | |
234 | |
235 // Handle arrays of primitive types | |
236 if (arrayElementType.equals("boolean")) { | |
237 arrayRef = env.newBooleanArray(vals.length); | |
238 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
239 boolean bools[] = arrayEI.asBooleanArray(); | |
240 | |
241 for (int i = 0; i < vals.length; i++) { | |
242 bools[i] = vals[i].getBoolean(); | |
243 } | |
244 } else if (arrayElementType.equals("byte")) { | |
245 arrayRef = env.newByteArray(vals.length); | |
246 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
247 byte bytes[] = arrayEI.asByteArray(); | |
248 | |
249 for (int i = 0; i < vals.length; i++) { | |
250 bytes[i] = vals[i].getDouble().byteValue(); | |
251 } | |
252 } else if (arrayElementType.equals("short")) { | |
253 arrayRef = env.newShortArray(vals.length); | |
254 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
255 short shorts[] = arrayEI.asShortArray(); | |
256 | |
257 for (int i = 0; i < vals.length; i++) { | |
258 shorts[i] = vals[i].getDouble().shortValue(); | |
259 } | |
260 } else if (arrayElementType.equals("int")) { | |
261 arrayRef = env.newIntArray(vals.length); | |
262 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
263 int[] ints = arrayEI.asIntArray(); | |
264 | |
265 for (int i = 0; i < vals.length; i++) { | |
266 ints[i] = vals[i].getDouble().intValue(); | |
267 } | |
268 } else if (arrayElementType.equals("long")) { | |
269 arrayRef = env.newLongArray(vals.length); | |
270 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
271 long[] longs = arrayEI.asLongArray(); | |
272 | |
273 for (int i = 0; i < vals.length; i++) { | |
274 longs[i] = vals[i].getDouble().longValue(); | |
275 } | |
276 } else if (arrayElementType.equals("float")) { | |
277 arrayRef = env.newFloatArray(vals.length); | |
278 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
279 float[] floats = arrayEI.asFloatArray(); | |
280 | |
281 for (int i = 0; i < vals.length; i++) { | |
282 floats[i] = vals[i].getDouble().floatValue(); | |
283 } | |
284 } else if (arrayElementType.equals("double")) { | |
285 arrayRef = env.newDoubleArray(vals.length); | |
286 ElementInfo arrayEI = env.getHeap().getModifiable(arrayRef); | |
287 double[] doubles = arrayEI.asDoubleArray(); | |
288 | |
289 for (int i = 0; i < vals.length; i++) { | |
290 doubles[i] = vals[i].getDouble(); | |
291 } | |
292 } else { | |
293 // Not an array of primitive types | |
294 arrayRef = env.newObjectArray(arrayElementType, vals.length); | |
295 ElementInfo arrayEI = env.getModifiableElementInfo(arrayRef); | |
296 | |
297 Fields fields = arrayEI.getFields(); | |
298 | |
299 Creator creator = CreatorsFactory.getCreator(arrayElementType); | |
300 for (int i = 0; i < vals.length; i++) { | |
301 | |
302 int newObjRef; | |
303 if (creator != null) { | |
304 newObjRef = creator.create(env, arrayElementType, vals[i]); | |
305 } else{ | |
306 if (isArrayType(arrayElementType)) { | |
307 newObjRef = createArray(env, ciElement, vals[i], cgs, prefix + "[" + i); | |
308 } else { | |
309 JSONObject jsonObj = vals[i].getObject(); | |
310 if (jsonObj != null) { | |
311 newObjRef = jsonObj.fillObject(env, ciElement, cgs, prefix + "[" + i); | |
312 } else { | |
313 newObjRef = MJIEnv.NULL; | |
314 } | |
315 } | |
316 } | |
317 | |
318 fields.setReferenceValue(i, newObjRef); | |
319 } | |
320 } | |
321 | |
322 return arrayRef; | |
323 } | |
324 | |
325 | |
326 private boolean isArrayType(String typeName) { | |
327 return typeName.lastIndexOf('[') >= 0; | |
328 } | |
329 | |
330 /** | |
331 * This is method is used to set field of primitive type from CG result object | |
332 * @param ei - ElementInfo to set field in | |
333 * @param fi - FieldInfo of a field we want to set | |
334 * @param cgResult - result of CG call | |
335 */ | |
336 private void convertPrimititve(ElementInfo ei, FieldInfo fi, Object cgResult) { | |
337 String primitiveName = fi.getType(); | |
338 | |
339 if (primitiveName.equals("boolean") && cgResult instanceof Boolean) { | |
340 Boolean bool = (Boolean) cgResult; | |
341 ei.setBooleanField(fi, bool.booleanValue()); | |
342 } else if (cgResult instanceof Number) { | |
343 Number number = (Number) cgResult; | |
344 | |
345 if (primitiveName.equals("byte")) { | |
346 ei.setByteField(fi, number.byteValue()); | |
347 | |
348 } else if (primitiveName.equals("short")) { | |
349 ei.setShortField(fi, number.shortValue()); | |
350 | |
351 } else if (primitiveName.equals("int")) { | |
352 ei.setIntField(fi, number.intValue()); | |
353 | |
354 } else if (primitiveName.equals("long")) { | |
355 ei.setLongField(fi, number.longValue()); | |
356 | |
357 } else if (primitiveName.equals("float")) { | |
358 ei.setFloatField(fi, number.floatValue()); | |
359 | |
360 } else if (primitiveName.equals("double")) { | |
361 ei.setDoubleField(fi, number.doubleValue()); | |
362 } | |
363 } else if (cgResult instanceof Character) { | |
364 Character c = (Character) cgResult; | |
365 ei.setCharField(fi, c); | |
366 | |
367 } else { | |
368 throw new JPFException("Can't convert " + cgResult.getClass().getCanonicalName() + | |
369 " to " + primitiveName); | |
370 } | |
371 } | |
372 | |
373 /** | |
374 * Get CG from current state CG list by it's ID | |
375 * @param cgs - array of CG from current state | |
376 * @param id - id of the CG that we search for | |
377 * @return - CG with a specified id or null if no id with such name found | |
378 */ | |
379 private ChoiceGenerator<?> getCGByID(ChoiceGenerator<?>[] cgs, String id) { | |
380 if (cgs == null) { | |
381 return null; | |
382 } | |
383 | |
384 for (int i = 0; i < cgs.length; i++) { | |
385 if (cgs[i].getId().equals(id)) { | |
386 return cgs[i]; | |
387 } | |
388 } | |
389 | |
390 return null; | |
391 } | |
392 } |