diff --git a/release-notes/VERSION b/release-notes/VERSION
index c071fcf870..d0129ead22 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -10,6 +10,8 @@ Project: jackson-databind
#113: Problem deserializing polymorphic types with @JsonCreator
#165: Add `DeserializationContext.getContextualType()` to let deserializer
known the expected type.
+#299: Add `DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS` to allow missing
+ Object Ids (as global default)
#408: External type id does not allow use of 'visible=true'
#421: @JsonCreator not used in case of multiple creators with parameter names
(reported by Lovro P, lpandzic@github)
diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java
index f048a4d155..6086743862 100644
--- a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java
+++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java
@@ -172,6 +172,22 @@ public enum DeserializationFeature implements ConfigFeature
*/
FAIL_ON_IGNORED_PROPERTIES(false),
+ /**
+ * 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 (true), or a null object is used
+ * instead (false).
+ * Note that if this is set to false, no further processing is done;
+ * specifically, if reference is defined via setter method, that method will NOT
+ * be called.
+ *
+ * Feature is enabled by default, so that unknown Object Ids will result in an
+ * exception being thrown, at the end of deserialization.
+ *
+ * @since 2.5
+ */
+ FAIL_ON_UNRESOLVED_OBJECT_IDS(true),
+
/**
* Feature that determines whether Jackson code should catch
* and wrap {@link Exception}s (but never {@link Error}s!)
@@ -188,7 +204,7 @@ public enum DeserializationFeature implements ConfigFeature
* Feature is enabled by default.
*/
WRAP_EXCEPTIONS(true),
-
+
/*
/******************************************************
/* Structural conversion features
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
index 72ecc78aa0..fd579391dd 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
@@ -138,7 +138,10 @@ public void checkUnresolvedObjectId() throws UnresolvedForwardReference
if (_objectIds == null) {
return;
}
-
+ // 29-Dec-2014, tatu: As per [databind#299], may also just let unresolved refs be...
+ if (!isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)) {
+ return;
+ }
UnresolvedForwardReference exception = null;
for (Entry entry : _objectIds.entrySet()) {
ReadableObjectId roid = entry.getValue();
@@ -146,7 +149,7 @@ public void checkUnresolvedObjectId() throws UnresolvedForwardReference
if (exception == null) {
exception = new UnresolvedForwardReference("Unresolved forward references for: ");
}
- for (Iterator iterator = roid.referringProperties(); iterator.hasNext();) {
+ for (Iterator iterator = roid.referringProperties(); iterator.hasNext(); ) {
Referring referring = iterator.next();
exception.addUnresolvedId(roid.getKey().key, referring.getBeanType(), referring.getLocation());
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/ContainerSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/ContainerSerializer.java
index ac08200969..119a2d8545 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/ContainerSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/ContainerSerializer.java
@@ -84,18 +84,25 @@ public ContainerSerializer> withValueTypeSerializer(TypeSerializer vts) {
* {@link com.fasterxml.jackson.databind.SerializerProvider#findValueSerializer}.
*/
public abstract JsonSerializer> getContentSerializer();
-
+
/*
/**********************************************************
/* Abstract methods for sub-classes to implement
/**********************************************************
*/
-
+
/* Overridden as abstract, to force re-implementation; necessary for all
* collection types.
*/
@Override
- public abstract boolean isEmpty(T value);
+ @Deprecated
+ public boolean isEmpty(T value) {
+ return isEmpty(null, value);
+ }
+
+ // since 2.5: should be declared abstract in future (2.6)
+// @Override
+// public abstract boolean isEmpty(SerializerProvider prov, T value);
/**
* Method called to determine if the given value (of type handled by
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/IndexedListSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/IndexedListSerializer.java
index a7ff0f50f9..346c2cc6d9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/IndexedListSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/IndexedListSerializer.java
@@ -47,7 +47,7 @@ public IndexedListSerializer withResolved(BeanProperty property,
*/
@Override
- public boolean isEmpty(List> value) {
+ public boolean isEmpty(SerializerProvider prov, List> value) {
return (value == null) || value.isEmpty();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/IteratorSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/IteratorSerializer.java
index 0a77d721de..77737b1458 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/IteratorSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/IteratorSerializer.java
@@ -28,7 +28,7 @@ public IteratorSerializer(IteratorSerializer src,
}
@Override
- public boolean isEmpty(Iterator> value) {
+ public boolean isEmpty(SerializerProvider prov, Iterator> value) {
return (value == null) || !value.hasNext();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/MapEntrySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/MapEntrySerializer.java
index 165ebbe08f..e987cd5e49 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/MapEntrySerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/MapEntrySerializer.java
@@ -174,7 +174,7 @@ public boolean hasSingleElement(Map.Entry,?> value) {
}
@Override
- public boolean isEmpty(Entry, ?> value) {
+ public boolean isEmpty(SerializerProvider prov, Entry, ?> value) {
return (value == null);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
index d64c8c8cf0..72e88b0fb7 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
@@ -130,7 +130,7 @@ public JsonSerializer> getContentSerializer() {
}
@Override
- public boolean isEmpty(String[] value) {
+ public boolean isEmpty(SerializerProvider prov, String[] value) {
return (value == null) || (value.length == 0);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/CollectionSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/CollectionSerializer.java
index 1b32c344b3..09bc66ba49 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/CollectionSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/CollectionSerializer.java
@@ -62,7 +62,7 @@ public CollectionSerializer withResolved(BeanProperty property,
*/
@Override
- public boolean isEmpty(Collection> value) {
+ public boolean isEmpty(SerializerProvider prov, Collection> value) {
return (value == null) || value.isEmpty();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumMapSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumMapSerializer.java
index 48a2c80ac5..84a5b4fd95 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumMapSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumMapSerializer.java
@@ -162,7 +162,7 @@ public JsonSerializer> getContentSerializer() {
}
@Override
- public boolean isEmpty(EnumMap extends Enum>,?> value) {
+ public boolean isEmpty(SerializerProvider prov, EnumMap extends Enum>,?> value) {
return (value == null) || value.isEmpty();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSetSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSetSerializer.java
index cf0487cd91..5a63d20986 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSetSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSetSerializer.java
@@ -35,7 +35,7 @@ public EnumSetSerializer withResolved(BeanProperty property,
}
@Override
- public boolean isEmpty(EnumSet extends Enum>> value) {
+ public boolean isEmpty(SerializerProvider prov, EnumSet extends Enum>> value) {
return (value == null) || value.isEmpty();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/IterableSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/IterableSerializer.java
index 3879d9b2fa..7b3f9e0e09 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/IterableSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/IterableSerializer.java
@@ -38,7 +38,7 @@ public IterableSerializer withResolved(BeanProperty property,
}
@Override
- public boolean isEmpty(Iterable> value) {
+ public boolean isEmpty(SerializerProvider prov, Iterable> value) {
// Not really good way to implement this, but has to do for now:
return (value == null) || !value.iterator().hasNext();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
index 1029f3474b..ce020d157f 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
@@ -401,7 +401,7 @@ public JsonSerializer> getContentSerializer() {
}
@Override
- public boolean isEmpty(Map,?> value) {
+ public boolean isEmpty(SerializerProvider prov, Map,?> value) {
return (value == null) || value.isEmpty();
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
index 7579345ace..ad76e7c6d9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
@@ -174,7 +174,7 @@ public JsonSerializer> getContentSerializer() {
}
@Override
- public boolean isEmpty(Object[] value) {
+ public boolean isEmpty(SerializerProvider prov, Object[] value) {
return (value == null) || (value.length == 0);
}
@@ -190,8 +190,7 @@ public boolean hasSingleElement(Object[] value) {
*/
@Override
- public final void serialize(Object[] value, JsonGenerator jgen, SerializerProvider provider)
- throws IOException, JsonGenerationException
+ public final void serialize(Object[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException
{
final int len = value.length;
if ((len == 1) && provider.isEnabled(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)) {
@@ -204,8 +203,7 @@ public final void serialize(Object[] value, JsonGenerator jgen, SerializerProvid
}
@Override
- public void serializeContents(Object[] value, JsonGenerator jgen, SerializerProvider provider)
- throws IOException, JsonGenerationException
+ public void serializeContents(Object[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException
{
final int len = value.length;
if (len == 0) {
@@ -262,8 +260,7 @@ public void serializeContents(Object[] value, JsonGenerator jgen, SerializerProv
}
public void serializeContentsUsing(Object[] value, JsonGenerator jgen, SerializerProvider provider,
- JsonSerializer