Fix UserDeserializer is called only once for an array of json objects… (#271)


diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java
index 8d83a38..6e939ce 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2019 Payara Foundation and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
@@ -125,7 +125,7 @@
         }
 
         //Third deserializer is a supported value type to deserialize to JSON_VALUE
-        if (isJsonValueEvent()) {
+        if (isJsonValueEvent(jsonEvent)) {
             final Optional<AbstractValueTypeDeserializer<?>> supportedTypeDeserializer = getSupportedTypeDeserializer(rawType);
             if (!supportedTypeDeserializer.isPresent()) {
                 if (jsonEvent == JsonParser.Event.VALUE_NULL) {
@@ -178,8 +178,14 @@
         throw new JsonbException("unresolved type for deserialization: " + getRuntimeType());
     }
 
-    private boolean isJsonValueEvent() {
-        switch (jsonEvent) {
+    /**
+     * Checks if event is a value event.
+     *
+     * @param event JSON event to check.
+     * @return True if one of value events.
+     */
+    public static boolean isJsonValueEvent(JsonParser.Event event) {
+        switch (event) {
             case VALUE_NULL:
             case VALUE_FALSE:
             case VALUE_TRUE:
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java
index e4968d1..000328b 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -63,8 +63,9 @@
         JsonParser.Event lastEvent = parserContext.getLastEvent();
         final UserDeserializerParser userDeserializerParser = new UserDeserializerParser(parser);
         deserializerResult = (T) deserializerBinding.getJsonbDeserializer().deserialize(userDeserializerParser, context, getRuntimeType());
-        //Avoid moving parser to the end of the object, if deserializer was for one value only.
-        if (lastEvent == JsonParser.Event.START_ARRAY || lastEvent == JsonParser.Event.START_OBJECT) {
+        //In case deserialized structure is json object or array and the parser is not advanced
+        //after enclosing bracket of deserialized object.
+        if (parser.getCurrentLevel() == parserContext && !DeserializerBuilder.isJsonValueEvent(lastEvent)) {
             userDeserializerParser.advanceParserToEnd();
         }
     }
diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
index eb1acd3..c5d9a55 100644
--- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
+++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
+import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -28,11 +29,15 @@
 import java.util.TimeZone;
 import java.util.TreeMap;
 
+import javax.json.JsonObject;
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbBuilder;
 import javax.json.bind.JsonbConfig;
 import javax.json.bind.JsonbException;
 import javax.json.bind.config.PropertyOrderStrategy;
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.stream.JsonParser;
 
 import org.eclipse.yasson.TestTypeToken;
 import org.eclipse.yasson.internal.model.ReverseTreeMap;
@@ -447,6 +452,37 @@
         assertEquals("{\"null\":\"value\"}", jsonb.toJson(singletonMap(null, "value")));
     }
 
+    @Test
+    public void testDeserializeArrayWithAdvancingParserAfterObjectEnd() {
+        String json = "[{\"stringProperty\":\"Property 1 value\"},{\"stringProperty\":\"Property 2 value\"}]";
+        Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withDeserializers(new SimplePojoDeserializer()));
+        SimplePojo[] result = jsonb.fromJson(json, SimplePojo[].class);
+        Assert.assertEquals(2, result.length);
+    }
+
+    public class SimplePojoDeserializer implements JsonbDeserializer<SimplePojo> {
+        @Override
+        public SimplePojo deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
+            //parser.getObject advances the parser to END_OBJECT.
+            JsonObject json = parser.getObject();
+            SimplePojo simplePojo = new SimplePojo();
+            simplePojo.setStringProperty(json.getString("stringProperty"));
+            return simplePojo;
+        }
+    }
+
+    public class SimplePojo {
+        private String stringProperty;
+
+        public String getStringProperty() {
+            return stringProperty;
+        }
+
+        public void setStringProperty(String stringProperty) {
+            this.stringProperty = stringProperty;
+        }
+    }
+
     private Box createPojoWithDates() {
         Date date = getExpectedDate();
         Box box = createPojo();