NodeMapper { public <T> T deserialize(Node value, Class<T> into) { return deserializeNext(value, "", into, Object.class, this); }  void setSerializeNullValues(boolean serializeNullValues); boolean getSerializeNullValues(); void setWhenMissingSetter(WhenMissing whenMissing); WhenMissing getWhenMissingSetter(); void disableToNodeForClass(Class type); void enableToNodeForClass(Class type); Set<Class> getDisableToNode(); void disableFromNodeForClass(Class type); void enableFromNodeForClass(Class type); Set<Class> getDisableFromNode(); boolean getOmitEmptyValues(); void setOmitEmptyValues(boolean omitEmptyValues); Node serialize(Object object); T deserialize(Node value, Class<T> into); T deserializeInto(Node value, T objectToMutate); @SuppressWarnings("unchecked") V deserializeCollection(
            Node value,
            Class<T> into,
            Class<U> members
    ); @SuppressWarnings("unchecked") V deserializeMap(
            Node value, Class<T> into,
            Class<U> members
    );  }
@Test public void deserializesWithFromNodeFactoryAndUnknownPropertiesWithWarning() { Node baz = Node.parse("{\"foo\": \"hi\", \"baz\": 10, \"inner\": {\"inner\": {\"noSetter!\": \"inn!\"}}}"); Baz result = new NodeMapper().deserialize(baz, Baz.class); assertThat(result.toString(), equalTo( "Baz{foo='hi', baz=10, inner=Baz{foo='null', baz=0, inner=Baz{foo='null', baz=0, inner=null}}}")); }
@Test public void detectsWhenFromNodeFails() { NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(Node.objectNode(), FailingFromNode.class)); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create software.amazon.smithy.model.node.NodeMapperTest.FailingFromNode " + "from {}: Unable to deserialize Node using fromNode method: nope")); }
@Test public void deserializesWithFallThroughFromNodeFactory() { Node baz = Node.from("hello!"); assertThat(new NodeMapper().deserialize(baz, SimpleString.class).value, equalTo("hello!")); }
@Test public void deserializesWithBuilder() { Node traitValue = Node.parse("{\"min\": 10, \"max\": 100}"); NodeMapper mapper = new NodeMapper(); RangeTrait trait = mapper.deserialize(traitValue, RangeTrait.class); assertThat(trait.getMin().get().intValue(), equalTo(10)); assertThat(trait.getMax().get().intValue(), equalTo(100)); }
@Test public void deserializesWithBuilderCatchesErrorCreatingBuilder() { Node value = Node.parse("{\"foo\": \"foo\"}"); NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(value, ClassThrowingBuilderMethod.class)); assertThat(e.getMessage(), startsWith( "Deserialization error at (/): unable to create " + "software.amazon.smithy.model.node.NodeMapperTest.ClassThrowingBuilderMethod from " + "{\"foo\":\"foo\"}: Unable to deserialize Node using a builder: nope")); }
@Test public void deserializesIntoExactTypes() { NodeMapper mapper = new NodeMapper(); assertThat(mapper.deserialize(Node.from("hi"), StringNode.class), equalTo(Node.from("hi"))); assertThat(mapper.deserialize(Node.from(true), BooleanNode.class), equalTo(Node.from(true))); }
@Test @SuppressWarnings("unchecked") public void deserializesIntoObjectTypesForHomogeneousMap() { Node value = Node.parse("{\"min\": 10, \"max\": 100}"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(value, Object.class); assertThat(result, instanceOf(Map.class)); assertThat(((Map<String, Object>) result), hasKey("min")); assertThat(((Map<String, Object>) result), hasKey("max")); }
@Test @SuppressWarnings("unchecked") public void deserializesIntoObjectTypesForHeterogeneousMap() { Node value = Node.parse("{\"min\": 10, \"max\": \"100\", \"foo\": true}"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(value, Object.class); assertThat(result, instanceOf(Map.class)); assertThat(((Map<String, Object>) result).get("min"), equalTo(10L)); assertThat(((Map<String, Object>) result).get("max"), equalTo("100")); assertThat(((Map<String, Object>) result).get("foo"), equalTo(true)); }
@Test public void deserializesIntoBooleans() { NodeMapper mapper = new NodeMapper(); assertThat(mapper.deserialize(Node.from(true), Boolean.class), equalTo(true)); assertThat(mapper.deserialize(Node.from(true), boolean.class), equalTo(true)); assertThat(mapper.deserialize(Node.from(true), Object.class), equalTo(true)); }
@Test public void deserializesIntoNulls() { NodeMapper mapper = new NodeMapper(); assertThat(mapper.deserialize(Node.nullNode(), String.class), nullValue()); }
@Test public void deserializesStrings() { Node value = Node.from("hi"); NodeMapper mapper = new NodeMapper(); assertThat(mapper.deserialize(value, Object.class), equalTo("hi")); assertThat(mapper.deserialize(value, String.class), equalTo("hi")); }
@Test public void deserializesShapeIds() { Node value = Node.from("com.foo#Bar"); NodeMapper mapper = new NodeMapper(); assertThat(mapper.deserialize(value, ShapeId.class), equalTo(ShapeId.from("com.foo#Bar"))); }
@Test public void failsToConvertObjectNodeToList() { Node value = Node.parse("{\"min\": 10, \"max\": 100}"); Assertions.assertThrows(NodeDeserializationException.class, () -> { new NodeMapper().deserialize(value, List.class); }); }
@Test @SuppressWarnings("unchecked") public void deserializesArrayObject() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(value, Object.class); assertThat((ArrayList<Object>) result, contains("a", "b")); }
@Test @SuppressWarnings("unchecked") public void deserializesIterable() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(value, Iterable.class); assertThat(result, instanceOf(ArrayList.class)); assertThat((ArrayList<Object>) result, contains("a", "b")); }
@Test @SuppressWarnings("unchecked") public void deserializesCollection() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(value, Collection.class); assertThat(result, instanceOf(ArrayList.class)); assertThat((ArrayList<Object>) result, contains("a", "b")); }
@Test public void cannotDeserializeNonCollectionArrays() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Throwable e = Assertions.assertThrows(NodeDeserializationException.class, () -> { mapper.deserialize(value, PojoWithCollection.class); }); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create " + "software.amazon.smithy.model.node.NodeMapperTest.PojoWithCollection from [\"a\",\"b\"]")); }
@Test public void detectsWhenUnableToAddToCollection() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Throwable e = Assertions.assertThrows(NodeDeserializationException.class, () -> { mapper.deserialize(value, ThrowingCollectionOnAdd.class); }); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create " + "software.amazon.smithy.model.node.NodeMapperTest.ThrowingCollectionOnAdd from [\"a\",\"b\"]: " + "Cannot add a")); }
@Test public void detectsWhenUnableToCreateCollection() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Throwable e = Assertions.assertThrows(NodeDeserializationException.class, () -> { mapper.deserialize(value, ThrowingCollectionOnCreate.class); }); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create " + "software.amazon.smithy.model.node.NodeMapperTest.ThrowingCollectionOnCreate from [\"a\",\"b\"]: " + "Unable to deserialize array into Collection: nope")); }
@Test public void detectsWhenUnableToFindCollectionConstructorAndContinues() { Node value = Node.fromStrings("a", "b"); NodeMapper mapper = new NodeMapper(); Throwable e = Assertions.assertThrows(NodeDeserializationException.class, () -> { mapper.deserialize(value, NonZeroArgConstructorCollection.class); }); assertThat(e.getMessage(), equalTo( "Unable to find a zero-arg constructor for Collection " + "software.amazon.smithy.model.node.NodeMapperTest$NonZeroArgConstructorCollection")); }
@SuppressWarnings("unchecked") @Test public void deserializedFromObjectIntoObjectMap() { Node mappings = Node.parse("{\"foo\":\"foo\"}"); NodeMapper mapper = new NodeMapper(); Object result = mapper.deserialize(mappings, Object.class); assertThat(result, instanceOf(HashMap.class)); assertThat(((Map<String, Object>) result).get("foo"), equalTo("foo")); }
@SuppressWarnings("unchecked") @Test public void deserializedFromObjectIntoMap() { Node mappings = Node.parse("{\"foo\":\"foo\"}"); NodeMapper mapper = new NodeMapper(); Map<String, Object> result = mapper.deserialize(mappings, Map.class); assertThat(result, instanceOf(HashMap.class)); assertThat(result.get("foo"), equalTo("foo")); }
@SuppressWarnings("unchecked") @Test public void deserializedFromObjectIntoHashMap() { Node mappings = Node.parse("{\"foo\":\"foo\"}"); NodeMapper mapper = new NodeMapper(); Map<String, Object> result = mapper.deserialize(mappings, HashMap.class); assertThat(result, instanceOf(HashMap.class)); assertThat(result.get("foo"), equalTo("foo")); }
@Test public void throwsWhenMapDoesNotHaveZeroArgConstructor() { Node object = Node.objectNode(); NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(object, NoZeroArgCtorMap.class)); assertThat(e.getMessage(), equalTo( "Unable to find a zero-arg constructor for Map " + "software.amazon.smithy.model.node.NodeMapperTest$NoZeroArgCtorMap")); }
@Test public void throwsWhenMapCtorThrows() { Node object = Node.objectNode(); NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(object, BadMapCtor.class)); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create software.amazon.smithy.model.node.NodeMapperTest.BadMapCtor " + "from {}: Unable to deserialize object into Map: nope")); }
@Test public void detectsWhenBeanCtorFails() { NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(Node.objectNode(), FailingCtor.class)); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create software.amazon.smithy.model.node.NodeMapperTest.FailingCtor " + "from {}: Unable to deserialize a Node when invoking target constructor: nope")); }
@Test public void deserializesIntoValueWithSourceLocation() { NodeMapper mapper = new NodeMapper(); Map<StringNode, Node> mappings = new HashMap<>(); mappings.put(StringNode.from("foo"), StringNode.from("foo")); SourceLocation sourceLocation = new SourceLocation("/abc/def"); Node node = new ObjectNode(mappings, sourceLocation); HasSourceLocation hasSourceLocation = mapper.deserialize(node, HasSourceLocation.class); assertThat(sourceLocation, equalTo(hasSourceLocation.sourceLocation)); }
@Test public void deserializesEnums() { NodeMapper mapper = new NodeMapper(); assertThat(FooEnum.FOO, equalTo(mapper.deserialize(Node.from("foo"), FooEnum.class))); assertThat(FooEnum.BAZ, equalTo(mapper.deserialize(Node.from("Baz"), FooEnum.class))); assertThat(FooEnum.BAR, equalTo(mapper.deserialize(Node.from("BAR"), FooEnum.class))); }
@Test public void throwsWhenUnableToDeserializeEnums() { NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(Node.from("invalid"), FooEnum.class)); assertThat(e.getMessage(), equalTo( "Deserialization error at (/): unable to create software.amazon.smithy.model.node.NodeMapperTest.FooEnum " + "from \"invalid\": Expected one of the following enum strings: [foo, Baz, BAR]")); }
@Test public void failsWhenUnableToParsePattern() { NodeMapper mapper = new NodeMapper(); Node input = Node.from("["); Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(input, Pattern.class)); }
@Test public void deserializesWildcards() { NodeMapper mapper = new NodeMapper(); Node input = Node.objectNode().withMember("values", Node.fromStrings("a", "b")); HasWildcard result = mapper.deserialize(input, HasWildcard.class); assertThat(result.getValues(), contains("a", "b")); }
@Test public void doesNotSupportNonStaticInnerClasses() { NodeMapper mapper = new NodeMapper(); NodeDeserializationException e = Assertions.assertThrows( NodeDeserializationException.class, () -> mapper.deserialize(Node.objectNode(), NonStatic.class)); assertThat(e.getMessage(), containsString("Cannot create non-static inner class")); }
@Test public void deserializesWithCamelCase() { NodeMapper mapper = new NodeMapper(); Node input = Node.objectNode() .withMember("set.me.here", "hi1") .withMember("set.Me.Here.too", "hi2") .withMember("ignore..me", "hi3"); CamelCase result = mapper.deserialize(input, CamelCase.class); assertThat(result.getSetMeHere(), equalTo("hi1")); assertThat(result.getSetMeHereToo(), equalTo("hi2")); assertThat(result.getIgnoreMe(), nullValue()); }