ObjectBuilder { @SuppressWarnings("unchecked") public static <T extends Map<String, ?>> T createObject(Class<T> mapClass, Type genericType, JsonValue jsonObject) throws JsonException { if (jsonObject == null || jsonObject.isNull()) { return null; } Class mapValueClass; Type mapValueType; if (genericType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)genericType; if (!String.class.isAssignableFrom((Class)parameterizedType.getActualTypeArguments()[0])) { throw new JsonException("Key of Map must be String. "); } mapValueType = parameterizedType.getActualTypeArguments()[1]; if (mapValueType instanceof Class) { mapValueClass = (Class)mapValueType; } else if (mapValueType instanceof ParameterizedType) { mapValueClass = (Class)((ParameterizedType)mapValueType).getRawType(); } else { throw new JsonException( String.format("This type of Map can't be restored from JSON source.\nMap is parameterized by wrong Type: %s", parameterizedType)); } } else { throw new JsonException("Map is not parameterized. Map<Sting, ?> is not supported."); } Constructor<? extends T> constructor; if (mapClass.isInterface() || Modifier.isAbstract(mapClass.getModifiers())) { constructor = getConstructor(findAcceptableMapImplementation(mapClass), Map.class); } else { constructor = getConstructor(mapClass, Map.class); } Types jsonMapValueType = getType(mapValueClass); HashMap<String, Object> sourceMap = new HashMap<>(jsonObject.size()); Iterator<String> keys = jsonObject.getKeys(); while (keys.hasNext()) { String key = keys.next(); JsonValue childJsonValue = jsonObject.getElement(key); if (jsonMapValueType == null) { sourceMap.put(key, createObject(mapValueClass, childJsonValue)); } else { switch (jsonMapValueType) { case BYTE: case SHORT: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case CHAR: case STRING: case NULL: case ARRAY_BYTE: case ARRAY_SHORT: case ARRAY_INT: case ARRAY_LONG: case ARRAY_FLOAT: case ARRAY_DOUBLE: case ARRAY_BOOLEAN: case ARRAY_CHAR: case ARRAY_STRING: case CLASS: sourceMap.put(key, createObjectKnownTypes(mapValueClass, childJsonValue)); break; case ARRAY_OBJECT: sourceMap.put(key, createArray(mapValueClass, childJsonValue)); break; case COLLECTION: sourceMap.put(key, createCollection(mapValueClass, mapValueType, childJsonValue)); break; case MAP: sourceMap.put(key, createObject(mapValueClass, mapValueType, childJsonValue)); break; case ENUM: sourceMap.put(key, createEnum(mapValueClass, childJsonValue)); break; } } } try { return constructor.newInstance(sourceMap); } catch (Exception e) { throw new JsonException(e.getMessage(), e); } } private  ObjectBuilder(); static Object createArray(Class<?> aClass, JsonValue jsonArray); @SuppressWarnings("unchecked") static T createCollection(Class<T> collectionClass, Type genericType, JsonValue jsonArray); @SuppressWarnings("unchecked") static T createObject(Class<T> mapClass, Type genericType, JsonValue jsonObject); @SuppressWarnings({"unchecked"}) static T createObject(Class<T> aClass, JsonValue jsonValue);  }
@Test public void returnsNullWhenCreateObjectFromNull() throws Exception { assertNull(ObjectBuilder.createObject(Book.class, null)); }
@Test public void returnsNullWhenCreateObjectFromNullValue() throws Exception { assertNull(ObjectBuilder.createObject(Book.class, new NullValue())); }
@Test public void createsObject() throws Exception { ObjectValue jsonBook = createJsonBook(createJunitBook()); Book book = ObjectBuilder.createObject(Book.class, jsonBook); assertEquals(createJunitBook(), book); }
@Test public void createsEnum() throws Exception { StringValue enumName = new StringValue(JUNIT_IN_ACTION.name()); BookEnum book = ObjectBuilder.createObject(BookEnum.class, enumName); assertEquals(JUNIT_IN_ACTION, book); }
@Test public void failsCreateObjectWhenJsonValueIsNotObject() throws Exception { thrown.expect(JsonException.class); ObjectBuilder.createObject(Book.class, new StringValue("")); }
@Test public void failsCreateObjectWhenClassDoesNotHaveSimpleConstructor() throws Exception { thrown.expect(JsonException.class); ObjectValue jsonBook = createJsonBook(createJunitBook()); ObjectBuilder.createObject(NoSimpleConstructorBook.class, jsonBook); }
@Test public void createsProxyObjectForInterface() throws Exception { ObjectValue jsonBook = createJsonBook(createJunitBook()); IBook book = ObjectBuilder.createObject(IBook.class, jsonBook); assertEquals("Vincent Massol", book.getAuthor()); assertEquals("JUnit in Action", book.getTitle()); assertEquals(386, book.getPages()); assertEquals(19.37, book.getPrice(), 0.01); assertEquals(93011099534534L, book.getIsdn()); assertEquals(false, book.getAvailability()); assertEquals(false, book.getDelivery()); }
@Test public void throwsJsonExceptionWhenConstructorThrowsExceptionWhileInstanceOfClassCreated() throws Exception { thrown.expect(JsonException.class); ObjectValue jsonBook = createJsonBook(createJunitBook()); ObjectBuilder.createObject(ThrowsExceptionInConstructorBook.class, jsonBook); }
@Test public void createsMapOfStringToString() throws Exception { ObjectValue jsonObject = new ObjectValue(); jsonObject.addElement("1", new StringValue("to be or")); jsonObject.addElement("2", new StringValue("not to be")); Map map = ObjectBuilder.createObject(Map.class, newParameterizedType(Map.class, String.class, String.class), jsonObject); assertEquals(ImmutableMap.of("1", "to be or", "2", "not to be"), map); }
@Test public void createsObjectWithChildCollections() throws Exception { ObjectValue jsonObject = givenJsonObjectThatContainsCollections(); BookCollections bookCollections = ObjectBuilder.createObject(BookCollections.class, jsonObject); assertEquals(createBookCollections(), bookCollections); }
@Test public void createsSimpleGroovyBean() throws Exception { Class<?> aClass = parseGroovyClass("SimpleBean.groovy"); JsonValue jsonObject = createJsonObject("value", new StringValue("test restore groovy bean")); GroovyObject simpleBean = (GroovyObject)ObjectBuilder.createObject(aClass, jsonObject); assertEquals("test restore groovy bean", simpleBean.invokeMethod("getValue", new Object[0])); }
@Test public void createsComplexGroovyBean() throws Exception { Class<?> aBookClass = parseGroovyClass("BookBean.groovy"); Class<?> aStorageClass = parseGroovyClass("BookStorage.groovy"); GroovyObject junitBook = (GroovyObject)aBookClass.getDeclaredMethod("createJunitBook").invoke(null); GroovyObject cSharpBook = (GroovyObject)aBookClass.getDeclaredMethod("createCSharpBook").invoke(null); GroovyObject javaScriptBook = (GroovyObject)aBookClass.getDeclaredMethod("createJavaScriptBook").invoke(null); JsonValue jsonObject = createJsonObject("books", createJsonArray(createJsonBook(junitBook), createJsonBook(cSharpBook), createJsonBook(javaScriptBook))); GroovyObject groovyObject = (GroovyObject)ObjectBuilder.createObject(aStorageClass, jsonObject); assertEquals(aStorageClass.getDeclaredMethod("createBookStorage").invoke(null), groovyObject); }