Fix #1978
diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x
index e8f14df..4119859 100644
--- a/release-notes/CREDITS-2.x
+++ b/release-notes/CREDITS-2.x
@@ -762,3 +762,8 @@
Timur Shakurov (saladinkzn@github)
* Reported #1947: `MapperFeature.AUTO_DETECT_XXX` do not work if all disabled
(2.9.5)
+
+roeltje25@github
+ * Reported #1978: Using @JsonUnwrapped annotation in builderdeserializer hangs in
+ infinite loop
+ (2.9.5)
diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x
index c730c25..7c10c19 100644
--- a/release-notes/VERSION-2.x
+++ b/release-notes/VERSION-2.x
@@ -25,6 +25,8 @@
(reported by Timur S)
#1977: Serializing an Iterator with multiple sub-types fails after upgrading to 2.9.x
(reported by ssivanand@github)
+#1978: Using @JsonUnwrapped annotation in builderdeserializer hangs in infinite loop
+ (reported by roeltje25@github)
2.9.4 (24-Jan-2018)
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java
index b1ae5c1..2518574 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java
@@ -259,7 +259,7 @@
throws IOException
{
Object bean = _valueInstantiator.createUsingDefault(ctxt);
- for (; p.getCurrentToken() != JsonToken.END_OBJECT; p.nextToken()) {
+ for (; p.getCurrentToken() == JsonToken.FIELD_NAME; p.nextToken()) {
String propName = p.getCurrentName();
// Skip field name:
p.nextToken();
@@ -304,7 +304,7 @@
return deserializeWithView(p, ctxt, bean, view);
}
}
- for (; p.getCurrentToken() != JsonToken.END_OBJECT; p.nextToken()) {
+ for (; p.getCurrentToken() == JsonToken.FIELD_NAME; p.nextToken()) {
String propName = p.getCurrentName();
// Skip field name:
p.nextToken();
@@ -535,8 +535,7 @@
}
final Class<?> activeView = _needViewProcesing ? ctxt.getActiveView() : null;
-
- for (; p.getCurrentToken() != JsonToken.END_OBJECT; p.nextToken()) {
+ for (; p.getCurrentToken() == JsonToken.FIELD_NAME; p.nextToken()) {
String propName = p.getCurrentName();
p.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName);
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderInfiniteLoop1978Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderInfiniteLoop1978Test.java
new file mode 100644
index 0000000..0a6a067
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/builder/BuilderInfiniteLoop1978Test.java
@@ -0,0 +1,95 @@
+package com.fasterxml.jackson.databind.deser.builder;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+import com.fasterxml.jackson.databind.*;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+public class BuilderInfiniteLoop1978Test extends BaseMapTest
+{
+ static class Builder
+ {
+ private SubBean temp;
+ private int id;
+
+ Builder(@JsonProperty("beanId") int beanId) {
+ this.id = beanId;
+ }
+
+ @JsonUnwrapped(prefix="sub.")
+ public Builder withThing(SubBean thing) {
+ this.temp = thing;
+ return this;
+ }
+
+ public Bean build()
+ {
+ Bean bean = new Bean(id);
+ bean.setThing( temp );
+ return bean;
+ }
+ }
+
+ @JsonDeserialize(builder = Builder.class)
+ static class Bean
+ {
+ int id;
+ SubBean thing;
+
+ public Bean(int id) {
+ this.id = id;
+ }
+
+ public SubBean getThing() {
+ return thing;
+ }
+
+ public void setThing( SubBean thing ) {
+ this.thing = thing;
+ }
+ }
+
+ static class SubBuilder
+ {
+ private int element1;
+ private String element2;
+
+ @JsonProperty("el1")
+ public SubBuilder withElement1(int e1) {
+ this.element1 = e1;
+ return this;
+ }
+
+ public SubBean build()
+ {
+ SubBean bean = new SubBean();
+ bean.element1 = element1;
+ bean.element2 = element2;
+ return bean;
+ }
+ }
+
+ @JsonDeserialize(builder = SubBuilder.class)
+ static class SubBean
+ {
+ public int element1;
+ public String element2;
+ }
+
+ /*
+ /**********************************************************************
+ /* Test methods
+ /**********************************************************************
+ */
+
+ // for [databind#1978]
+ public void testInfiniteLoop1978() throws Exception
+ {
+ String json = "{\"sub.el1\":34,\"sub.el2\":\"some text\"}";
+ ObjectMapper mapper = new ObjectMapper();
+ Bean bean = mapper.readValue( json, Bean.class );
+ assertNotNull(bean);
+ }
+}