Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,9 @@ public enum DeserializationFeature implements ConfigFeature
/**
* Feature that determines what happens if an Object Id reference is encountered
* that does not refer to an actual Object with that id ("unresolved Object Id"):
* either an exception is thrown (<code>true</code>), or a null object is used
* instead (<code>false</code>).
* either an exception {@link com.fasterxml.jackson.databind.deser.UnresolvedForwardReference}
* containing information about {@link com.fasterxml.jackson.databind.deser.UnresolvedId}
* is thrown (<code>true</code>), or a null object is used instead (<code>false</code>).
* Note that if this is set to <code>false</code>, no further processing is done;
* specifically, if reference is defined via setter method, that method will NOT
* be called.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,26 @@ public ObjectIdResolver newForDeserialization(Object c)
}
}

static class SomeWrapper {
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@id")
public SomeNode node;

public SomeWrapper() {}

public SomeWrapper(int v) {
node = new SomeNode(v);
}
}

static class SomeNode {
public int value;
public SomeWrapper next;

public SomeNode() {this(0);}

public SomeNode(int v) {value = v;}
}

/*
/*****************************************************
/* Unit tests, external id deserialization
Expand Down Expand Up @@ -466,4 +486,60 @@ public void testNullObjectId() throws Exception
assertNotNull(value);
assertEquals(3, value.value);
}

/*
/*****************************************************
/* Unit tests in conjunction with DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS
/*****************************************************
*/


private final ObjectMapper DEFAULT_MAPPER = newJsonMapper();

private final ObjectMapper DISABLED_MAPPER = newJsonMapper()
.configure(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going forward let's try to use JsonMapper.builder() so code will merge and work with 3.0. I will change this after merging.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! 🙏🏼🙏🏼


private final ObjectMapper ENABLED_MAPPER = newJsonMapper()
.configure(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS, true);

public void testDefaultSetting() {
assertTrue(DEFAULT_MAPPER.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS));
assertTrue(ENABLED_MAPPER.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS));
assertFalse(DISABLED_MAPPER.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS));
}

public void testSuccessResolvedObjectIds() throws Exception {
String json = a2q("{'node':{'@id':1,'value':7,'next':{'node':1}}}");

SomeWrapper wrapper = DEFAULT_MAPPER.readValue(json, SomeWrapper.class);

assertSame(wrapper.node, wrapper.node.next.node);
assertSame(wrapper.node.next.node, wrapper.node.next.node.next.node);
}

public void testUnresolvedObjectIdsFailure() throws Exception {
// Set-up : node id of 2 that doesn't exist,
String json = a2q("{'node':{'@id':1,'value':7,'next':{'node':2}}}");

// 1. Does not fail, because disabled such.
SomeWrapper wrapper = DISABLED_MAPPER.readValue(json, SomeWrapper.class);
assertNull(wrapper.node.next.node);

try {
// 2. Will fail by default.
DEFAULT_MAPPER.readValue(json, SomeWrapper.class);
fail("should not pass");
} catch (UnresolvedForwardReference e) {
verifyException(e, "Unresolved forward reference", "Object id [2]");
}

try {
// 3. Will also throw exception, because configured as such.
ENABLED_MAPPER.readValue(json, SomeWrapper.class);
fail("should not pass");
} catch (UnresolvedForwardReference e) {
verifyException(e, "Unresolved forward reference", "Object id [2]");
}
}

}