diff --git a/release-notes/CREDITS b/release-notes/CREDITS index bed2b1590a..0927fbdff4 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -459,6 +459,8 @@ William Headrick (headw01@github) Nick Babcock (nickbabcock) * Reported #1225: `JsonMappingException` should override getProcessor() (2.7.5) + * Suggested #1356: Differentiate between input and code exceptions on deserialization + (2.9.0) Andrew Joseph (apjoseph@github) * Reported #1248: `Annotated` returns raw type in place of Generic Type in 2.7.x diff --git a/release-notes/VERSION b/release-notes/VERSION index 8b32174d7a..48ffeaff09 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -8,6 +8,8 @@ Project: jackson-databind #1341: FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY (contributed by Connor K) +#1356: Differentiate between input and code exceptions on deserialization + (suggested by Nick B) #1369: Improve `@JsonCreator` detection via `AnnotationIntrospector` by passing `MappingConfig` #1371: Add `MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES` to allow diff --git a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java index f42a0bb1e9..d3d0e60683 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java @@ -224,4 +224,19 @@ public Converter converterInstance(Annotated annotated, } return (Converter) conv; } + + /* + /********************************************************** + /* Error reporting + /********************************************************** + */ + + /** + * Helper method called to indicate a generic problem that stems from type + * definition(s), not input data, or input/output state; typically this + * means throwing a {@link com.fasterxml.jackson.databind.exc.InvalidDefinitionException}. + * + * @since 2.9 + */ + public abstract T reportBadDefinition(JavaType type, String msg) throws JsonMappingException; } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 0609c1e68e..3f42961f1f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -3,7 +3,11 @@ import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; -import java.util.*; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.annotation.JsonFormat; @@ -15,6 +19,8 @@ import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId; import com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer; +import com.fasterxml.jackson.databind.exc.InputMismatchException; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; @@ -31,14 +37,14 @@ * Used to allow passing in configuration settings and reusable temporary * objects (scrap arrays, containers). *

- * Instance life-cycle is such that an partially configured "blueprint" object + * Instance life-cycle is such that a partially configured "blueprint" object * is registered with {@link ObjectMapper} (and {@link ObjectReader}, - * and when an actual instance is needed for deserialization, - * a fully configured instance will - * be created using a method in excented API of sub-class + * and when actual instance is needed for deserialization, + * a fully configured instance will be created using a method in extended internal + * API of sub-class * ({@link com.fasterxml.jackson.databind.deser.DefaultDeserializationContext#createInstance}). * Each instance is guaranteed to only be used from single-threaded context; - * instances may be reused iff no configuration has changed. + * instances may be reused if (and only if) no configuration has changed. *

* Defined as abstract class so that implementations must define methods * for reconfiguring blueprints and creating instances. @@ -765,7 +771,8 @@ public T readValue(JsonParser p, Class type) throws IOException { public T readValue(JsonParser p, JavaType type) throws IOException { JsonDeserializer deser = findRootValueDeserializer(type); if (deser == null) { - reportMappingException("Could not find JsonDeserializer for type %s", type); + reportBadDefinition(type, + "Could not find JsonDeserializer for type "+type); } return (T) deser.deserialize(p, this); } @@ -790,9 +797,9 @@ public T readPropertyValue(JsonParser p, BeanProperty prop, JavaType type) t JsonDeserializer deser = findContextualValueDeserializer(type, prop); if (deser == null) { String propName = (prop == null) ? "NULL" : ("'"+prop.getName()+"'"); - reportMappingException( + return reportBadDefinition(type, String.format( "Could not find JsonDeserializer for type %s (via property %s)", - type, propName); + type, propName)); } return (T) deser.deserialize(p, this); } @@ -1105,7 +1112,8 @@ public Object handleUnexpectedToken(Class instClass, JsonToken t, if ((instance == null) || instClass.isInstance(instance)) { return instance; } - reportMappingException("DeserializationProblemHandler.handleUnexpectedToken() for type %s returned value of type %s", + reportInputMismatch( + "DeserializationProblemHandler.handleUnexpectedToken() for type %s returned value of type %s", instClass, instance.getClass()); } h = h.next(); @@ -1119,7 +1127,7 @@ public Object handleUnexpectedToken(Class instClass, JsonToken t, _calcName(instClass), t); } } - reportMappingException(msg); + reportInputMismatch(msg); return null; // never gets here } @@ -1173,7 +1181,7 @@ public JavaType handleUnknownTypeId(JavaType baseType, String id, /* /********************************************************** /* Methods for problem reporting, in cases where recovery - /* is not considered possible + /* is not considered possible: input problem /********************************************************** */ @@ -1222,18 +1230,6 @@ public void reportUnknownProperty(Object instanceOrClass, String fieldName, instanceOrClass, fieldName, propIds); } - /** - * @since 2.8 - */ - public void reportMappingException(String msg, Object... msgArgs) - throws JsonMappingException - { - if (msgArgs.length > 0) { - msg = String.format(msg, msgArgs); - } - throw JsonMappingException.from(getParser(), msg); - } - /** * @since 2.8 */ @@ -1245,20 +1241,65 @@ public void reportMissingContent(String msg, Object... msgArgs) } else if (msgArgs.length > 0) { msg = String.format(msg, msgArgs); } - throw JsonMappingException.from(getParser(), msg); + throw InputMismatchException.from(getParser(), msg); } /** * @since 2.8 */ - public void reportUnresolvedObjectId(ObjectIdReader oidReader, Object bean) + public T reportUnresolvedObjectId(ObjectIdReader oidReader, Object bean) throws JsonMappingException { String msg = String.format("No Object Id found for an instance of %s, to assign to property '%s'", bean.getClass().getName(), oidReader.propertyName); - throw JsonMappingException.from(getParser(), msg); + return reportInputMismatch(oidReader.idProperty, msg); + } + + /** + * Helper method used to indicate a problem with input in cases where more + * specific reportXxx() method was not available. + * + * @since 2.9 + */ + public T reportInputMismatch(BeanProperty prop, String msg) + throws JsonMappingException + { + throw InputMismatchException.from(getParser(), msg); } + /** + * Helper method used to indicate a problem with input in cases where more + * specific reportXxx() method was not available. + * + * @since 2.9 + */ + public T reportInputMismatch(JsonDeserializer src, String msg) + throws JsonMappingException + { + throw InputMismatchException.from(getParser(), msg); + } + + /** + * Helper method used to indicate a problem with input in cases where more + * specific reportXxx() method was not available. + * + * @since 2.9 + */ + public T reportInputMismatch(String msg, Object... msgArgs) throws JsonMappingException + { + if (msgArgs.length > 0) { + msg = String.format(msg, msgArgs); + } + throw InputMismatchException.from(getParser(), msg); + } + + /* + /********************************************************** + /* Methods for problem reporting, in cases where recovery + /* is not considered possible: POJO definition problems + /********************************************************** + */ + /** * Helper method called to indicate problem in POJO (serialization) definitions or settings * regarding specific Java type, unrelated to actual JSON content to map. @@ -1272,8 +1313,8 @@ public T reportBadTypeDefinition(BeanDescription bean, message = String.format(message, args); } String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); - throw mappingException("Invalid type definition for type %s: %s", - beanDesc, message); + message = String.format("Invalid type definition for type %s: %s", beanDesc, message); + throw InvalidDefinitionException.from(_parser, message, bean, null); } /** @@ -1290,64 +1331,15 @@ public T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefin } String propName = (prop == null) ? "N/A" : _quotedString(prop.getName()); String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); - throw mappingException("Invalid definition for property %s (of type %s): %s", + message = String.format ( + "Invalid definition for property %s (of type %s): %s", propName, beanDesc, message); + throw InvalidDefinitionException.from(_parser, message, bean, prop); } - /* - /********************************************************** - /* Methods for constructing exceptions, "untyped" - /********************************************************** - */ - - /** - * Helper method for constructing generic mapping exception with specified - * message and current location information. - * Note that application code should almost always call - * one of handleXxx methods, or {@link #reportMappingException(String, Object...)} - * instead. - * - * @since 2.6 - */ - public JsonMappingException mappingException(String message) { - return JsonMappingException.from(getParser(), message); - } - - /** - * Helper method for constructing generic mapping exception with specified - * message and current location information - * Note that application code should almost always call - * one of handleXxx methods, or {@link #reportMappingException(String, Object...)} - * instead. - * - * @since 2.6 - */ - public JsonMappingException mappingException(String msgTemplate, Object... args) { - if (args != null && args.length > 0) { - msgTemplate = String.format(msgTemplate, args); - } - return JsonMappingException.from(getParser(), msgTemplate); - } - - /** - * Helper method for constructing generic mapping exception for specified type - * - * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead - */ - @Deprecated - public JsonMappingException mappingException(Class targetClass) { - return mappingException(targetClass, _parser.getCurrentToken()); - } - - /** - * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead - */ - @Deprecated - public JsonMappingException mappingException(Class targetClass, JsonToken token) { - String tokenDesc = (token == null) ? "" : String.format("%s token", token); - return JsonMappingException.from(_parser, - String.format("Can not deserialize instance of %s out of %s", - _calcName(targetClass), tokenDesc)); + @Override + public T reportBadDefinition(JavaType type, String msg) throws JsonMappingException { + throw InvalidDefinitionException.from(_parser, msg, type); } /* @@ -1373,7 +1365,7 @@ public JsonMappingException wrongTokenException(JsonParser p, JsonToken expToken if (msg0 != null) { msg = msg + ": "+msg0; } - return JsonMappingException.from(p, msg); + return InputMismatchException.from(p, msg); } /** @@ -1437,10 +1429,14 @@ public JsonMappingException weirdNumberException(Number value, Class instClas * {@link #handleInstantiationProblem} should be called which will call this method * if necessary. */ - public JsonMappingException instantiationException(Class instClass, Throwable t) { - return JsonMappingException.from(_parser, - String.format("Can not construct instance of %s, problem: %s", - instClass.getName(), t.getMessage()), t); + public JsonMappingException instantiationException(Class instClass, Throwable cause) { + // Most likely problem with Creator definition, right? + JavaType type = constructType(instClass); + String msg = String.format("Can not construct instance of %s, problem: %s", + instClass.getName(), cause.getMessage()); + InvalidDefinitionException e = InvalidDefinitionException.from(_parser, msg, type); + e.initCause(cause); + return e; } /** @@ -1452,10 +1448,11 @@ public JsonMappingException instantiationException(Class instClass, Throwable * {@link #handleMissingInstantiator} should be called which will call this method * if necessary. */ - public JsonMappingException instantiationException(Class instClass, String msg) { - return JsonMappingException.from(_parser, - String.format("Can not construct instance of %s: %s", - instClass.getName(), msg)); + public JsonMappingException instantiationException(Class instClass, String msg0) { + // Most likely problem with Creator definition, right? + JavaType type = constructType(instClass); + String msg = String.format("Can not construct instance of %s: %s", instClass.getName(), msg0); + return InvalidDefinitionException.from(_parser, msg, type); } /** @@ -1511,6 +1508,89 @@ public JsonMappingException endOfInputException(Class instClass) { +instClass.getName()); } + /* + /********************************************************** + /* Deprecated methods for constructing, throwing non-specific + /* JsonMappingExceptions: as of 2.9, should use more specific + /* ones. + /********************************************************** + */ + + /** + * Fallback method that may be called if no other reportXxx + * is applicable -- but only in that case. + * + * @since 2.8 + * + * @deprecate Since 2.9: use a more specific method, or {@link #reportBadDefinition(JavaType, String)}, + * or {@link #reportInputMismatch(String, Object...)} instead + */ + @Deprecated // since 2.9 + public void reportMappingException(String msg, Object... msgArgs) + throws JsonMappingException + { + if (msgArgs.length > 0) { + msg = String.format(msg, msgArgs); + } + throw JsonMappingException.from(getParser(), msg); + } + + /** + * Helper method for constructing generic mapping exception with specified + * message and current location information. + * Note that application code should almost always call + * one of handleXxx methods, or {@link #reportMappingException(String, Object...)} + * instead. + * + * @since 2.6 + * + * @deprecated Since 2.9 use more specific error reporting methods instead + */ + @Deprecated + public JsonMappingException mappingException(String message) { + return JsonMappingException.from(getParser(), message); + } + + /** + * Helper method for constructing generic mapping exception with specified + * message and current location information + * Note that application code should almost always call + * one of handleXxx methods, or {@link #reportMappingException(String, Object...)} + * instead. + * + * @since 2.6 + * + * @deprecated Since 2.9 use more specific error reporting methods instead + */ + @Deprecated + public JsonMappingException mappingException(String msgTemplate, Object... args) { + if (args != null && args.length > 0) { + msgTemplate = String.format(msgTemplate, args); + } + return JsonMappingException.from(getParser(), msgTemplate); + } + + /** + * Helper method for constructing generic mapping exception for specified type + * + * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead + */ + @Deprecated + public JsonMappingException mappingException(Class targetClass) { + return mappingException(targetClass, _parser.getCurrentToken()); + } + + /** + * @deprecated Since 2.8 use {@link #handleUnexpectedToken(Class, JsonParser)} instead + */ + @Deprecated + public JsonMappingException mappingException(Class targetClass, JsonToken token) { + String tokenDesc = (token == null) ? "" : String.format("%s token", token); + return JsonMappingException.from(_parser, + String.format("Can not deserialize instance of %s out of %s", + _calcName(targetClass), tokenDesc)); + } + /* /********************************************************** /* Other internal methods diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java index 5c7f742db3..4d30531f56 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java @@ -319,7 +319,10 @@ public static JsonMappingException from(SerializerProvider ctxt, String msg, Thr * a signature. * * @since 2.1 + * + * @deprecated Since 2.9 call method on {@link InputMismatchException} instead */ + @Deprecated public static JsonMappingException fromUnexpectedIOE(IOException src) { return new JsonMappingException(null, String.format("Unexpected IOException (of type %s): %s", diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java index 3506cd2c1d..08152aab1f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonSerializer.java @@ -157,8 +157,9 @@ public void serializeWithType(T value, JsonGenerator gen, SerializerProvider ser if (clz == null) { clz = value.getClass(); } - serializers.reportMappingProblem("Type id handling not implemented for type %s (by serializer of type %s)", - clz.getName(), getClass().getName()); + serializers.reportDefinitionProblem(clz, String.format( + "Type id handling not implemented for type %s (by serializer of type %s)", + clz.getName(), getClass().getName())); } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 0fef61ecbd..a9aff4c3cd 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -4,7 +4,15 @@ import java.lang.reflect.Type; import java.net.URL; import java.text.DateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; @@ -22,6 +30,7 @@ import com.fasterxml.jackson.databind.cfg.MutableConfigOverride; import com.fasterxml.jackson.databind.cfg.ConfigOverrides; import com.fasterxml.jackson.databind.deser.*; +import com.fasterxml.jackson.databind.exc.InputMismatchException; import com.fasterxml.jackson.databind.introspect.*; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; import com.fasterxml.jackson.databind.jsontype.*; @@ -3044,14 +3053,14 @@ public String writeValueAsString(Object value) SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler()); try { _configAndWriteValue(_jsonFactory.createGenerator(sw), value); - } catch (JsonProcessingException e) { // to support [JACKSON-758] + } catch (JsonProcessingException e) { throw e; } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: - throw JsonMappingException.fromUnexpectedIOE(e); + throw InputMismatchException.fromUnexpectedIOE(e); } return sw.getAndClear(); } - + /** * Method that can be used to serialize any Java value as * a byte array. Functionally equivalent to calling @@ -3071,7 +3080,7 @@ public byte[] writeValueAsBytes(Object value) } catch (JsonProcessingException e) { // to support [JACKSON-758] throw e; } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: - throw JsonMappingException.fromUnexpectedIOE(e); + throw InputMismatchException.fromUnexpectedIOE(e); } byte[] result = bb.toByteArray(); bb.release(); @@ -3824,7 +3833,7 @@ protected JsonToken _initForReading(JsonParser p) throws IOException if (t == null) { // Throw mapping exception, since it's failure to map, // not an actual parsing problem - throw JsonMappingException.from(p, "No content to map due to end-of-input"); + throw InputMismatchException.from(p, "No content to map due to end-of-input"); } } return t; @@ -3851,7 +3860,7 @@ protected Object _unwrapAndDeserialize(JsonParser p, DeserializationContext ctxt } String actualName = p.getCurrentName(); if (!expSimpleName.equals(actualName)) { - ctxt.reportMappingException("Root name '%s' does not match expected ('%s') for type %s", + ctxt.reportInputMismatch("Root name '%s' does not match expected ('%s') for type %s", actualName, expSimpleName, rootType); } // ok, then move to value itself.... @@ -3887,7 +3896,7 @@ protected JsonDeserializer _findRootDeserializer(DeserializationContext // Nope: need to ask provider to resolve it deser = ctxt.findRootValueDeserializer(valueType); if (deser == null) { // can this happen? - throw JsonMappingException.from(ctxt, + return ctxt.reportBadDefinition(valueType, "Can not find a deserializer for type "+valueType); } _rootDeserializers.put(valueType, deser); diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java index f006f82a3b..763ab5ab20 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java @@ -1687,7 +1687,7 @@ protected Object _unwrapAndDeserialize(JsonParser p, DeserializationContext ctxt } String actualName = p.getCurrentName(); if (!expSimpleName.equals(actualName)) { - ctxt.reportMappingException("Root name '%s' does not match expected ('%s') for type %s", + ctxt.reportInputMismatch("Root name '%s' does not match expected ('%s') for type %s", actualName, expSimpleName, rootType); } // ok, then move to value itself.... @@ -1844,9 +1844,8 @@ protected JsonDeserializer _findRootDeserializer(DeserializationContext // Sanity check: must have actual type... JavaType t = _valueType; if (t == null) { - ctxt.reportMappingException("No value type configured for ObjectReader"); + ctxt.reportBadDefinition(null, "No value type configured for ObjectReader"); } - // First: have we already seen it? JsonDeserializer deser = _rootDeserializers.get(t); if (deser != null) { @@ -1855,7 +1854,7 @@ protected JsonDeserializer _findRootDeserializer(DeserializationContext // Nope: need to ask provider to resolve it deser = ctxt.findRootValueDeserializer(t); if (deser == null) { // can this happen? - ctxt.reportMappingException("Can not find a deserializer for type %s", t); + ctxt.reportBadDefinition(t, "Can not find a deserializer for type "+t); } _rootDeserializers.put(t, deser); return deser; @@ -1872,8 +1871,8 @@ protected JsonDeserializer _findTreeDeserializer(DeserializationContext // Nope: need to ask provider to resolve it deser = ctxt.findRootValueDeserializer(JSON_NODE_TYPE); if (deser == null) { // can this happen? - ctxt.reportMappingException("Can not find a deserializer for type %s", - JSON_NODE_TYPE); + ctxt.reportBadDefinition(JSON_NODE_TYPE, + "Can not find a deserializer for type "+JSON_NODE_TYPE); } _rootDeserializers.put(JSON_NODE_TYPE, deser); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java b/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java index 9574c154ca..f481f1cab7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java @@ -2,7 +2,9 @@ import java.io.*; import java.text.*; -import java.util.*; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.core.*; @@ -12,6 +14,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.*; import com.fasterxml.jackson.databind.cfg.ContextAttributes; +import com.fasterxml.jackson.databind.exc.InputMismatchException; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.ser.*; @@ -1018,14 +1021,14 @@ public String writeValueAsString(Object value) SegmentedStringWriter sw = new SegmentedStringWriter(_generatorFactory._getBufferRecycler()); try { _configAndWriteValue(_generatorFactory.createGenerator(sw), value); - } catch (JsonProcessingException e) { // to support [JACKSON-758] + } catch (JsonProcessingException e) { throw e; } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: - throw JsonMappingException.fromUnexpectedIOE(e); + throw InputMismatchException.fromUnexpectedIOE(e); } return sw.getAndClear(); } - + /** * Method that can be used to serialize any Java value as * a byte array. Functionally equivalent to calling @@ -1045,7 +1048,7 @@ public byte[] writeValueAsBytes(Object value) } catch (JsonProcessingException e) { // to support [JACKSON-758] throw e; } catch (IOException e) { // shouldn't really happen, but is declared as possibility so: - throw JsonMappingException.fromUnexpectedIOE(e); + throw InputMismatchException.fromUnexpectedIOE(e); } byte[] result = bb.toByteArray(); bb.release(); diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java index bce67fae17..5f508a5bcd 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.cfg.ContextAttributes; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; @@ -445,6 +446,17 @@ public final FilterProvider getFilterProvider() { return _config.getFilterProvider(); } + /** + *

+ * NOTE: current implementation simply returns `null` as generator is not yet + * assigned to this provider. + * + * @since 2.8 + */ + public JsonGenerator getGenerator() { + return null; + } + /* /********************************************************** /* Access to Object Id aspects @@ -1097,42 +1109,55 @@ public final void defaultSerializeNull(JsonGenerator gen) throws IOException */ /** - * Factory method for constructing a {@link JsonMappingException}; - * usually only indirectly used by calling - * {@link #reportMappingProblem(String, Object...)}. + * Helper method called to indicate problem in POJO (serialization) definitions or settings + * regarding specific Java type, unrelated to actual JSON content to map. + * Default behavior is to construct and throw a {@link JsonMappingException}. * - * @since 2.6 + * @since 2.9 */ - public JsonMappingException mappingException(String message, Object... args) { + public T reportBadTypeDefinition(BeanDescription bean, + String message, Object... args) throws JsonMappingException { if (args != null && args.length > 0) { message = String.format(message, args); } - return JsonMappingException.from(getGenerator(), message); + String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); + message = String.format("Invalid type definition for type %s: %s", + beanDesc, message); + throw InvalidDefinitionException.from(getGenerator(), message, bean, null); } /** - * Factory method for constructing a {@link JsonMappingException}; - * usually only indirectly used by calling - * {@link #reportMappingProblem(Throwable, String, Object...)} - * - * @since 2.8 + * Helper method called to indicate problem in POJO (serialization) definitions or settings + * regarding specific property (of a type), unrelated to actual JSON content to map. + * Default behavior is to construct and throw a {@link JsonMappingException}. + * + * @since 2.9 */ - protected JsonMappingException mappingException(Throwable t, String message, Object... args) { + public T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefinition prop, + String message, Object... args) throws JsonMappingException { if (args != null && args.length > 0) { message = String.format(message, args); } - return JsonMappingException.from(getGenerator(), message, t); + String propName = (prop == null) ? "N/A" : _quotedString(prop.getName()); + String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); + message = String.format("Invalid definition for property %s (of type %s): %s", + propName, beanDesc, message); + throw InvalidDefinitionException.from(getGenerator(), message, bean, prop); + } + + @Override + public T reportBadDefinition(JavaType type, String msg) throws JsonMappingException { + throw InvalidDefinitionException.from(getGenerator(), msg, type); } /** - * Helper method called to indicate problem; default behavior is to construct and - * throw a {@link JsonMappingException}, but in future may collect more than one - * and only throw after certain number, or at the end of serialization. + * Helper method called to indicate a non-specific deserialization problem + * caused by a bad definition of a type. * - * @since 2.8 + * @since 2.9 */ - public void reportMappingProblem(String message, Object... args) throws JsonMappingException { - throw mappingException(message, args); + public T reportDefinitionProblem(Class type, String msg) throws JsonMappingException { + throw InvalidDefinitionException.from(getGenerator(), msg, constructType(type)); } /** @@ -1143,49 +1168,64 @@ public void reportMappingProblem(String message, Object... args) throws JsonMapp * @since 2.8 */ public void reportMappingProblem(Throwable t, String message, Object... args) throws JsonMappingException { - throw mappingException(t, message, args); + if (args != null && args.length > 0) { + message = String.format(message, args); + } + throw JsonMappingException.from(getGenerator(), message, t); } + /* + /******************************************************** + /* Error reporting, deprecated methods + /******************************************************** + */ + /** - * Helper method called to indicate problem in POJO (serialization) definitions or settings - * regarding specific Java type, unrelated to actual JSON content to map. - * Default behavior is to construct and throw a {@link JsonMappingException}. + * Factory method for constructing a {@link JsonMappingException}; + * usually only indirectly used by calling + * {@link #reportMappingProblem(String, Object...)}. * - * @since 2.9 + * @since 2.6 + * + * @deprecated Since 2.9 */ - public T reportBadTypeDefinition(BeanDescription bean, - String message, Object... args) throws JsonMappingException { + @Deprecated // since 2.9 + public JsonMappingException mappingException(String message, Object... args) { if (args != null && args.length > 0) { message = String.format(message, args); } - String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); - throw mappingException("Invalid type definition for type %s: %s", - beanDesc, message); + return JsonMappingException.from(getGenerator(), message); } /** - * Helper method called to indicate problem in POJO (serialization) definitions or settings - * regarding specific property (of a type), unrelated to actual JSON content to map. - * Default behavior is to construct and throw a {@link JsonMappingException}. + * Factory method for constructing a {@link JsonMappingException}; + * usually only indirectly used by calling + * {@link #reportMappingProblem(Throwable, String, Object...)} + * + * @since 2.8 * - * @since 2.9 + * @deprecated Since 2.9 */ - public T reportBadPropertyDefinition(BeanDescription bean, BeanPropertyDefinition prop, - String message, Object... args) throws JsonMappingException { + @Deprecated // since 2.9 + protected JsonMappingException mappingException(Throwable t, String message, Object... args) { if (args != null && args.length > 0) { message = String.format(message, args); } - String propName = (prop == null) ? "N/A" : _quotedString(prop.getName()); - String beanDesc = (bean == null) ? "N/A" : _desc(bean.getType().getGenericSignature()); - throw mappingException("Invalid definition for property %s (of type %s): %s", - propName, beanDesc, message); + return JsonMappingException.from(getGenerator(), message, t); } /** + * Helper method called to indicate problem; default behavior is to construct and + * throw a {@link JsonMappingException}, but in future may collect more than one + * and only throw after certain number, or at the end of serialization. + * * @since 2.8 + * + * @deprecated Since 2.9 */ - public JsonGenerator getGenerator() { - return null; + @Deprecated // since 2.9 + public void reportMappingProblem(String message, Object... args) throws JsonMappingException { + throw mappingException(message, args); } /* @@ -1204,8 +1244,9 @@ protected void _reportIncompatibleRootType(Object value, JavaType rootType) thro return; } } - reportMappingProblem("Incompatible types: declared root type (%s) vs %s", - rootType, value.getClass().getName()); + reportBadDefinition(rootType, String.format( + "Incompatible types: declared root type (%s) vs %s", + rootType, value.getClass().getName())); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index d498bad215..d80c23d03f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -260,7 +260,7 @@ public ValueInstantiator findValueInstantiator(DeserializationContext ctxt, instantiator = insts.findValueInstantiator(config, beanDesc, instantiator); // let's do sanity check; easier to spot buggy handlers if (instantiator == null) { - ctxt.reportMappingException( + ctxt.reportBadTypeDefinition(beanDesc, "Broken registered ValueInstantiators (of type %s): returned null ValueInstantiator", insts.getClass().getName()); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index 25d3a86669..958fbe1709 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -733,7 +733,8 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p, Deseri // !!! 08-Jul-2011, tatu: Could probably support; but for now // it's too complicated, so bail out tokens.close(); - ctxt.reportMappingException("Can not create polymorphic instances with unwrapped values"); + ctxt.reportInputMismatch(creatorProp, + "Can not create polymorphic instances with unwrapped values"); return null; } return _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens); @@ -899,8 +900,9 @@ protected Object deserializeUsingPropertyBasedWithExternalTypeId(JsonParser p, D if (bean.getClass() != _beanType.getRawClass()) { // !!! 08-Jul-2011, tatu: Could theoretically support; but for now // it's too complicated, so bail out - ctxt.reportMappingException("Can not create polymorphic instances with external type ids"); - return null; + return ctxt.reportBadDefinition(_beanType, String.format( + "Can not create polymorphic instances with external type ids (%s -> %s)", + _beanType, bean.getClass())); } return ext.complete(p, ctxt, bean); } @@ -978,7 +980,7 @@ public void setBean(Object bean) { public void handleResolvedForwardReference(Object id, Object value) throws IOException { if (_bean == null) { - _context.reportMappingException( + _context.reportInputMismatch( "Can not resolve ObjectId forward reference using property '%s' (of type %s): Bean not yet resolved", _prop.getName(), _prop.getDeclaringClass().getName()); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java index 7815e53fca..06217d2a63 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java @@ -548,7 +548,8 @@ protected void addBeanProps(DeserializationContext ctxt, } } if (cprop == null) { - ctxt.reportMappingException("Could not find creator property with name '%s' (in class %s)", + ctxt.reportBadTypeDefinition(beanDesc, + "Could not find creator property with name '%s' (in class %s)", name, beanDesc.getBeanClass().getName()); continue; } 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 7b92423cbe..4db6ef7ed7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BuilderBasedDeserializer.java @@ -600,7 +600,8 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p, if (bean.getClass() != _beanType.getRawClass()) { // !!! 08-Jul-2011, tatu: Could probably support; but for now // it's too complicated, so bail out - ctxt.reportMappingException("Can not create polymorphic instances with unwrapped values"); + ctxt.reportInputMismatch(creatorProp, + "Can not create polymorphic instances with unwrapped values"); return null; } return _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 0db15589b7..a83a7c155d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -567,25 +567,20 @@ private Class _verifyAsClass(Object src, String methodName, Class noneClas /********************************************************** */ - // NOTE: changed 2.6 -> 2.7 to pass context; no way to make backwards compatible protected JsonDeserializer _handleUnknownValueDeserializer(DeserializationContext ctxt, JavaType type) throws JsonMappingException { - /* Let's try to figure out the reason, to give better error - * messages - */ + // Let's try to figure out the reason, to give better error messages Class rawClass = type.getRawClass(); if (!ClassUtil.isConcrete(rawClass)) { - ctxt.reportMappingException("Can not find a Value deserializer for abstract type %s", type); + return ctxt.reportBadDefinition(type, "Can not find a Value deserializer for abstract type "+type); } - ctxt.reportMappingException("Can not find a Value deserializer for type %s", type); - return null; + return ctxt.reportBadDefinition(type, "Can not find a Value deserializer for type "+type); } protected KeyDeserializer _handleUnknownKeyDeserializer(DeserializationContext ctxt, JavaType type) throws JsonMappingException { - ctxt.reportMappingException("Can not find a (Map) Key deserializer for type %s", type); - return null; + return ctxt.reportBadDefinition(type, "Can not find a (Map) Key deserializer for type "+type); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayBuilderDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayBuilderDeserializer.java index dabe451ddf..ff14557f38 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayBuilderDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayBuilderDeserializer.java @@ -132,7 +132,7 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) } // Ok; extra fields? Let's fail, unless ignoring extra props is fine if (!_ignoreAllUnknown) { - ctxt.reportMappingException("Unexpected JSON values; expected at most %d properties (in JSON Array)", + ctxt.reportInputMismatch("Unexpected JSON values; expected at most %d properties (in JSON Array)", propCount); // fall through } @@ -314,10 +314,9 @@ protected final Object _deserializeUsingPropertyBased(final JsonParser p, * supported (since ordering of elements may not be guaranteed); * but make explicitly non-supported for now. */ - ctxt.reportMappingException("Can not support implicit polymorphic deserialization for POJOs-as-Arrays style: " - +"nominal type %s, actual type %s", - _beanType.getRawClass().getName(), builder.getClass().getName()); - return null; + return ctxt.reportBadDefinition(_beanType, String.format( +"Can not support implicit polymorphic deserialization for POJOs-as-Arrays style: nominal type %s, actual type %s", + _beanType.getRawClass().getName(), builder.getClass().getName())); } } continue; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayDeserializer.java index 1cff5ca46f..353af26711 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanAsArrayDeserializer.java @@ -314,9 +314,10 @@ protected final Object _deserializeUsingPropertyBased(final JsonParser p, final * supported (since ordering of elements may not be guaranteed); * but make explicitly non-supported for now. */ - ctxt.reportMappingException("Can not support implicit polymorphic deserialization for POJOs-as-Arrays style: " + ctxt.reportBadDefinition(_beanType, String.format( + "Can not support implicit polymorphic deserialization for POJOs-as-Arrays style: " +"nominal type %s, actual type %s", - _beanType.getRawClass().getName(), bean.getClass().getName()); + _beanType.getRawClass().getName(), bean.getClass().getName())); } } continue; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java index 4069f386f1..6106a20b22 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java @@ -157,7 +157,7 @@ public Object complete(JsonParser p, DeserializationContext ctxt, Object bean) } // 26-Oct-2012, tatu: As per [databind#94], must allow use of 'defaultImpl' if (!_properties[i].hasDefaultType()) { - ctxt.reportMappingException("Missing external type id property '%s'", + ctxt.reportInputMismatch("Missing external type id property '%s'", _properties[i].getTypePropertyName()); } else { typeId = _properties[i].getDefaultTypeId(); @@ -168,7 +168,7 @@ public Object complete(JsonParser p, DeserializationContext ctxt, Object bean) if(prop.isRequired() || ctxt.isEnabled(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY)) { - ctxt.reportMappingException("Missing property '%s' for external type id '%s'", + ctxt.reportInputMismatch("Missing property '%s' for external type id '%s'", prop.getName(), _properties[i].getTypePropertyName()); } return bean; @@ -201,14 +201,14 @@ public Object complete(JsonParser p, DeserializationContext ctxt, // but not just one // 26-Oct-2012, tatu: As per [databind#94], must allow use of 'defaultImpl' if (!extProp.hasDefaultType()) { - ctxt.reportMappingException("Missing external type id property '%s'", + ctxt.reportInputMismatch("Missing external type id property '%s'", extProp.getTypePropertyName()); } else { typeId = extProp.getDefaultTypeId(); } } else if (_tokens[i] == null) { SettableBeanProperty prop = extProp.getProperty(); - ctxt.reportMappingException("Missing property '%s' for external type id '%s'", + ctxt.reportInputMismatch("Missing property '%s' for external type id '%s'", prop.getName(), _properties[i].getTypePropertyName()); } values[i] = _deserialize(p, ctxt, i, typeId); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java index a777bdeb3c..906ab0455f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java @@ -24,7 +24,7 @@ public FailingDeserializer(String m) { @Override public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws JsonMappingException{ - ctxt.reportMappingException(_message); + ctxt.reportInputMismatch(_message); return null; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java index 42d33cadbd..bb4d7e3591 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java @@ -132,9 +132,9 @@ public Object getParameter(SettableBeanProperty prop) value = _creatorParameters[prop.getCreatorIndex()] = _findMissing(prop); } if (value == null && _context.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) { - throw _context.mappingException( + return _context.reportInputMismatch(prop, String.format( "Null value for creator property '%s'; DeserializationFeature.FAIL_ON_NULL_FOR_CREATOR_PARAMETERS enabled", - prop.getName(), prop.getCreatorIndex()); + prop.getName(), prop.getCreatorIndex())); } return value; } @@ -171,7 +171,7 @@ public Object[] getParameters(SettableBeanProperty[] props) if (_context.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) { for (int ix = 0; ix < props.length; ++ix) { if (_creatorParameters[ix] == null) { - _context.reportMappingException("Null value for creator property '%s'; DeserializationFeature.FAIL_ON_NULL_FOR_CREATOR_PARAMETERS enabled", + _context.reportInputMismatch("Null value for creator property '%s'; DeserializationFeature.FAIL_ON_NULL_FOR_CREATOR_PARAMETERS enabled", props[ix].getName(), props[ix].getCreatorIndex()); } } @@ -190,12 +190,14 @@ protected Object _findMissing(SettableBeanProperty prop) throws JsonMappingExcep } // Second: required? if (prop.isRequired()) { - _context.reportMappingException("Missing required creator property '%s' (index %d)", - prop.getName(), prop.getCreatorIndex()); + _context.reportInputMismatch(prop, String.format( + "Missing required creator property '%s' (index %d)", + prop.getName(), prop.getCreatorIndex())); } if (_context.isEnabled(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES)) { - _context.reportMappingException("Missing creator property '%s' (index %d); DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES enabled", - prop.getName(), prop.getCreatorIndex()); + _context.reportInputMismatch(prop, String.format( + "Missing creator property '%s' (index %d); DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES enabled", + prop.getName(), prop.getCreatorIndex())); } // Third: default value JsonDeserializer deser = prop.getValueDeserializer(); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/SetterlessProperty.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/SetterlessProperty.java index 1d7e5ba52c..bc0fe61a7b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/SetterlessProperty.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/SetterlessProperty.java @@ -99,11 +99,11 @@ public final void deserializeAndSet(JsonParser p, DeserializationContext ctxt, return; } - // For [#501] fix we need to implement this but: + // For [databind#501] fix we need to implement this but: if (_valueTypeDeserializer != null) { - ctxt.reportMappingException( + ctxt.reportBadDefinition(getType(), String.format( "Problem deserializing 'setterless' property (\"%s\"): no way to handle typed deser with setterless yet", - getName()); + getName())); // return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java index 1fdf9f4510..4a1f844a42 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java @@ -162,8 +162,9 @@ public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOExcepti protected T _deserializeEmbedded(Object ob, DeserializationContext ctxt) throws IOException { // default impl: error out - ctxt.reportMappingException("Don't know how to convert embedded Object of type %s into %s", - ob.getClass().getName(), _valueClass.getName()); + ctxt.reportInputMismatch(this, String.format( + "Don't know how to convert embedded Object of type %s into %s", + ob.getClass().getName(), _valueClass.getName())); return null; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java index 05b0562607..b6fa02a203 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java @@ -190,7 +190,7 @@ protected void _handleDuplicateField(JsonParser p, DeserializationContext ctxt, { // [databind#237]: Report an error if asked to do so: if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)) { - ctxt.reportMappingException("Duplicate field '%s' for ObjectNode: not allowed when FAIL_ON_READING_DUP_TREE_KEY enabled", + ctxt.reportInputMismatch("Duplicate field '%s' for ObjectNode: not allowed when FAIL_ON_READING_DUP_TREE_KEY enabled", fieldName); } } @@ -222,7 +222,8 @@ protected final ObjectNode deserializeObject(JsonParser p, DeserializationContex JsonNode value; JsonToken t = p.nextToken(); if (t == null) { - throw ctxt.mappingException("Unexpected end-of-input when binding data into ObjectNode"); + ctxt.reportMissingContent("Unexpected end-of-input when binding data into ObjectNode"); + return null; } switch (t.id()) { case JsonTokenId.ID_START_OBJECT: diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java index 3dc7c4b061..70a908c8f5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java @@ -455,7 +455,7 @@ protected final void _readAndBind(JsonParser p, DeserializationContext ctxt, result.put(key, value); } } catch (UnresolvedForwardReference reference) { - handleUnresolvedReference(p, referringAccumulator, key, reference); + handleUnresolvedReference(ctxt, referringAccumulator, key, reference); } catch (Exception e) { wrapAndThrow(e, result, keyStr); } @@ -514,7 +514,7 @@ protected final void _readAndBindStringKeyMap(JsonParser p, DeserializationConte result.put(key, value); } } catch (UnresolvedForwardReference reference) { - handleUnresolvedReference(p, referringAccumulator, key, reference); + handleUnresolvedReference(ctxt, referringAccumulator, key, reference); } catch (Exception e) { wrapAndThrow(e, result, key); } @@ -598,12 +598,14 @@ protected void wrapAndThrow(Throwable t, Object ref) throws IOException { wrapAndThrow(t, ref, null); } - private void handleUnresolvedReference(JsonParser jp, MapReferringAccumulator accumulator, + private void handleUnresolvedReference(DeserializationContext ctxt, + MapReferringAccumulator accumulator, Object key, UnresolvedForwardReference reference) throws JsonMappingException { if (accumulator == null) { - throw JsonMappingException.from(jp, "Unresolved forward reference but no identity info.", reference); + ctxt.reportInputMismatch("Unresolved forward reference but no identity info: %s", + reference); } Referring referring = accumulator.handleUnresolvedReference(reference, key); reference.getRoid().appendReferring(referring); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapEntryDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapEntryDeserializer.java index 78997121f3..54bf34c919 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/MapEntryDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/MapEntryDeserializer.java @@ -183,8 +183,8 @@ public Map.Entry deserialize(JsonParser p, DeserializationContext } if (t != JsonToken.FIELD_NAME) { if (t == JsonToken.END_OBJECT) { - ctxt.reportMappingException("Can not deserialize a Map.Entry out of empty JSON Object"); - return null; + return ctxt.reportInputMismatch(this, + "Can not deserialize a Map.Entry out of empty JSON Object"); } return (Map.Entry) ctxt.handleUnexpectedToken(handledType(), p); } @@ -215,10 +215,11 @@ public Map.Entry deserialize(JsonParser p, DeserializationContext t = p.nextToken(); if (t != JsonToken.END_OBJECT) { if (t == JsonToken.FIELD_NAME) { // most likely - ctxt.reportMappingException("Problem binding JSON into Map.Entry: more than one entry in JSON (second field: '"+p.getCurrentName()+"')"); + ctxt.reportInputMismatch("Problem binding JSON into Map.Entry: more than one entry in JSON (second field: '%s')", + p.getCurrentName()); } else { // how would this occur? - ctxt.reportMappingException("Problem binding JSON into Map.Entry: unexpected content after JSON Object entry: "+t); + ctxt.reportInputMismatch("Problem binding JSON into Map.Entry: unexpected content after JSON Object entry: "+t); } return null; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java index 1137dcd1c3..2472352163 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java @@ -132,7 +132,7 @@ protected PrimitiveOrWrapperDeserializer(Class vc, T nvl) { public final T getNullValue(DeserializationContext ctxt) throws JsonMappingException { if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) { - ctxt.reportMappingException( + ctxt.reportInputMismatch( "Can not map JSON null into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)", handledType().toString()); } @@ -144,7 +144,7 @@ public T getEmptyValue(DeserializationContext ctxt) throws JsonMappingException // [databind#1095]: Should not allow coercion from into null from Empty String // either, if `null` not allowed if (_primitive && ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) { - ctxt.reportMappingException( + ctxt.reportInputMismatch( "Can not map Empty String as null into type %s (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)", handledType().toString()); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java index 4221b30ade..813b85010d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java @@ -174,7 +174,7 @@ public char[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx str = cs.toString(); } if (str.length() != 1) { - ctxt.reportMappingException("Can not convert a JSON String of length %d into a char element of char array", + ctxt.reportInputMismatch("Can not convert a JSON String of length %d into a char element of char array", str.length()); } sb.append(str.charAt(0)); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java index f26c2dd789..21b5c05d25 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java @@ -1115,7 +1115,7 @@ protected void handleMissingEndArrayForSingle(JsonParser p, DeserializationConte protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt, String type) throws IOException { - ctxt.reportMappingException("Can not coerce a floating-point value ('%s') into %s; enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow", + ctxt.reportInputMismatch("Can not coerce a floating-point value ('%s') into %s; enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow", p.getValueAsString(), type); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/IgnoredPropertyException.java b/src/main/java/com/fasterxml/jackson/databind/exc/IgnoredPropertyException.java index c26d951043..793f0c8b0b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/exc/IgnoredPropertyException.java +++ b/src/main/java/com/fasterxml/jackson/databind/exc/IgnoredPropertyException.java @@ -39,7 +39,6 @@ public IgnoredPropertyException(String msg, JsonLocation loc, super(msg, loc, referringClass, propName, propertyIds); } - /** * Factory method used for constructing instances of this exception type. * diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/InputMismatchException.java b/src/main/java/com/fasterxml/jackson/databind/exc/InputMismatchException.java new file mode 100644 index 0000000000..19b19e7482 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/exc/InputMismatchException.java @@ -0,0 +1,43 @@ +package com.fasterxml.jackson.databind.exc; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonLocation; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.JsonMappingException; + +/** + * General exception type used as the base class for all {@link JsonMappingException}s + * that are due to input not mapping to target definition; these are typically + * considered "client errors" since target type definition itself is not the root cause + * but mismatching input. This is in contrast to {@link InvalidDefinitionException} which + * signals a problem with target type definition and not input. + *

+ * This type is used as-is for some input problems, but in most cases there should be + * more explicit subtypes to use. + * + * @since 2.9 + */ +@SuppressWarnings("serial") +public class InputMismatchException + extends JsonMappingException +{ + protected InputMismatchException(JsonParser p, String msg) { + super(p, msg); + } + + protected InputMismatchException(JsonParser p, String msg, JsonLocation loc) { + super(p, msg, loc); + } + + public static InputMismatchException from(JsonParser p, String msg) { + return new InputMismatchException(p, msg); + } + + @SuppressWarnings("deprecation") + public static InputMismatchException fromUnexpectedIOE(IOException src) { + return new InputMismatchException(null, + String.format("Unexpected IOException (of type %s): %s", + src.getClass().getName(), src.getMessage())); + } +} diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.java b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.java new file mode 100644 index 0000000000..b201eff9e6 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.java @@ -0,0 +1,104 @@ +package com.fasterxml.jackson.databind.exc; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; + +/** + * Intermediate exception type used as the base class for all {@link JsonMappingException}s + * that are due to problems with target type definition; usually a problem with + * annotations used on a class or its properties. + * This is in contrast to {@link InputMismatchException} which + * signals a problem with input to map. + * + * @since 2.9 + */ +@SuppressWarnings("serial") +public class InvalidDefinitionException + extends JsonMappingException +{ + protected final JavaType _type; + + protected transient BeanDescription _beanDesc; + protected transient BeanPropertyDefinition _property; + + protected InvalidDefinitionException(JsonParser p, String msg, + JavaType type) { + super(p, msg); + _type = type; + _beanDesc = null; + _property = null; + } + + protected InvalidDefinitionException(JsonGenerator g, String msg, + JavaType type) { + super(g, msg); + _type = type; + _beanDesc = null; + _property = null; + } + + protected InvalidDefinitionException(JsonParser p, String msg, + BeanDescription bean, BeanPropertyDefinition prop) { + super(p, msg); + _type = (bean == null) ? null : bean.getType(); + _beanDesc = bean; + _property = prop; + } + + protected InvalidDefinitionException(JsonGenerator g, String msg, + BeanDescription bean, BeanPropertyDefinition prop) { + super(g, msg); + _type = (bean == null) ? null : bean.getType(); + _beanDesc = bean; + _property = prop; + } + + public static InvalidDefinitionException from(JsonParser p, String msg, + BeanDescription bean, BeanPropertyDefinition prop) { + return new InvalidDefinitionException(p, msg, bean, prop); + } + + public static InvalidDefinitionException from(JsonParser p, String msg, + JavaType type) { + return new InvalidDefinitionException(p, msg, type); + } + + public static InvalidDefinitionException from(JsonGenerator g, String msg, + BeanDescription bean, BeanPropertyDefinition prop) { + return new InvalidDefinitionException(g, msg, bean, prop); + } + + public static InvalidDefinitionException from(JsonGenerator g, String msg, + JavaType type) { + return new InvalidDefinitionException(g, msg, type); + } + + /** + * Accessor for type fully resolved type that had the problem; this should always + * known and available, never null + */ + public JavaType getType() { + return _type; + } + + /** + * Accessor for type definition (class) that had the definition problem, if any; may sometimes + * be undefined or unknown; if so, returns null. + */ + public BeanDescription getBeanDescription() { + return _beanDesc; + } + + /** + * Accessor for property that had the definition problem if any + * (none, for example if the problem relates to type in general), + * if known. If not known (or relevant), returns null. + */ + public BeanPropertyDefinition getProperty() { + return _property; + } +} diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java index e7593d1451..974318d6e9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java +++ b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java @@ -11,7 +11,8 @@ * * @since 2.1 */ -public class InvalidFormatException extends JsonMappingException +public class InvalidFormatException + extends InputMismatchException // since 2.9 { private static final long serialVersionUID = 1L; // silly Eclipse, warnings diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidTypeIdException.java b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidTypeIdException.java index 8b05215d43..c6168a683f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidTypeIdException.java +++ b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidTypeIdException.java @@ -2,14 +2,14 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonMappingException; /** * Exception thrown when resolution of a type id fails. * * @since 2.8 */ -public class InvalidTypeIdException extends JsonMappingException +public class InvalidTypeIdException + extends InputMismatchException // since 2.9 { private static final long serialVersionUID = 1L; // silly Eclipse, warnings diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/PropertyBindingException.java b/src/main/java/com/fasterxml/jackson/databind/exc/PropertyBindingException.java index 2dcfe8a812..e4964c782e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/exc/PropertyBindingException.java +++ b/src/main/java/com/fasterxml/jackson/databind/exc/PropertyBindingException.java @@ -16,7 +16,7 @@ */ @SuppressWarnings("serial") public abstract class PropertyBindingException - extends JsonMappingException + extends InputMismatchException // since 2.9 { /** * Class that does not contain mapping for the unrecognized property. diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java index 7284b47b4f..0c217fe19c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java @@ -246,8 +246,7 @@ protected Object _deserializeWithNativeTypeId(JsonParser jp, DeserializationCont */ deser = _findDefaultImplDeserializer(ctxt); if (deser == null) { - ctxt.reportMappingException("No (native) type id found when one was expected for polymorphic type handling"); - return null; + return ctxt.reportInputMismatch("No (native) type id found when one was expected for polymorphic type handling"); } } else { String typeIdStr = (typeId instanceof String) ? (String) typeId : String.valueOf(typeId); diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java index bedf67eadd..8179a9f401 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java @@ -53,8 +53,9 @@ public void getAndSerialize(Object bean, JsonGenerator gen, SerializerProvider p return; } if (!(value instanceof Map)) { - provider.reportMappingProblem("Value returned by 'any-getter' %s() not java.util.Map but %s", - _accessor.getName(), value.getClass().getName()); + provider.reportBadDefinition(_property.getType(), String.format( + "Value returned by 'any-getter' %s() not java.util.Map but %s", + _accessor.getName(), value.getClass().getName())); } // 23-Feb-2015, tatu: Nasty, but has to do (for now) if (_mapSerializer != null) { @@ -76,8 +77,9 @@ public void getAndFilter(Object bean, JsonGenerator gen, SerializerProvider prov return; } if (!(value instanceof Map)) { - provider.reportMappingProblem("Value returned by 'any-getter' (%s()) not java.util.Map but %s", - _accessor.getName(), value.getClass().getName()); + provider.reportBadDefinition(_property.getType(), + String.format("Value returned by 'any-getter' (%s()) not java.util.Map but %s", + _accessor.getName(), value.getClass().getName())); } // 19-Oct-2014, tatu: Should we try to support @JsonInclude options here? if (_mapSerializer != null) { diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java index 49c87af6ff..0ffdd40f77 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanPropertyWriter.java @@ -918,7 +918,7 @@ protected boolean _handleSelfReference(Object bean, JsonGenerator gen, // (something // OTHER than {@link BeanSerializerBase} if (ser instanceof BeanSerializerBase) { - prov.reportMappingProblem("Direct self-reference leading to cycle"); + prov.reportBadDefinition(getType(), "Direct self-reference leading to cycle"); } } return false; diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java index bb0c72e640..5cc9540c2f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java @@ -98,6 +98,9 @@ protected BeanPropertyWriter buildWriter(SerializerProvider prov, try { serializationType = findSerializationType(am, defaultUseStaticTyping, declaredType); } catch (JsonMappingException e) { + if (propDef == null) { + return prov.reportBadDefinition(declaredType, e.getMessage()); + } return prov.reportBadPropertyDefinition(_beanDesc, propDef, e.getMessage()); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java index 6c1530b703..31c8ea953a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnknownSerializer.java @@ -66,7 +66,8 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t protected void failForEmpty(SerializerProvider prov, Object value) throws JsonMappingException { - prov.reportMappingProblem("No serializer found for class %s and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)", - value.getClass().getName()); + prov.reportDefinitionProblem(handledType(), String.format( + "No serializer found for class %s and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)", + value.getClass().getName())); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java index 834e03ac36..bfe7919efd 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/UnwrappingBeanSerializer.java @@ -126,7 +126,8 @@ public void serializeWithType(Object bean, JsonGenerator gen, SerializerProvider TypeSerializer typeSer) throws IOException { if (provider.isEnabled(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS)) { - provider.reportMappingProblem("Unwrapped property requires use of type information: can not serialize without disabling `SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS`"); + provider.reportDefinitionProblem(handledType(), + "Unwrapped property requires use of type information: can not serialize without disabling `SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS`"); } gen.setCurrentValue(bean); // [databind#631] if (_objectIdWriter != null) { diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java index 538796defe..00c40e18bf 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java @@ -424,18 +424,21 @@ public void writeTypeSuffixForArray(Object value, JsonGenerator gen) throws IOEx _typeSerializer.writeTypeSuffixForArray(_forObject, gen); } + @Override public void writeTypePrefixForScalar(Object value, JsonGenerator gen, Class type) throws IOException { _typeSerializer.writeTypePrefixForScalar(_forObject, gen, type); } + @Override public void writeTypePrefixForObject(Object value, JsonGenerator gen, Class type) throws IOException { _typeSerializer.writeTypePrefixForObject(_forObject, gen, type); } + @Override public void writeTypePrefixForArray(Object value, JsonGenerator gen, Class type) throws IOException { _typeSerializer.writeTypePrefixForArray(_forObject, gen, type); } - + @Override public void writeCustomTypePrefixForScalar(Object value, JsonGenerator gen, String typeId) throws IOException { 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 d71bc40305..f18c71d12f 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 @@ -378,7 +378,8 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t TypeFactory tf = visitor.getProvider().getTypeFactory(); JavaType contentType = tf.moreSpecificType(_elementType, typeHint.getContentType()); if (contentType == null) { - throw JsonMappingException.from(visitor.getProvider(), "Could not resolve type"); + visitor.getProvider().reportBadDefinition(_elementType, + "Could not resolve type: "+_elementType); } JsonSerializer valueSer = _elementSerializer; if (valueSer == null) { diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java index a1108e89de..ddf3b79261 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java @@ -438,7 +438,7 @@ protected PropertyFilter findPropertyFilter(SerializerProvider provider, FilterProvider filters = provider.getFilterProvider(); // Not ok to miss the provider, if a filter is declared to be needed. if (filters == null) { - throw JsonMappingException.from(provider, + provider.reportDefinitionProblem(handledType(), "Can not resolve PropertyFilter with id '"+filterId+"'; no FilterProvider configured"); } // But whether unknown ids are ok just depends on filter provider; if we get null that's fine diff --git a/src/test/java/com/fasterxml/jackson/databind/creators/TestCreators2.java b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreators2.java index f075bcb9f5..6f2e42c5e4 100644 --- a/src/test/java/com/fasterxml/jackson/databind/creators/TestCreators2.java +++ b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreators2.java @@ -176,6 +176,9 @@ public void testExceptionFromConstructor() throws Exception verifyException(e, ": foobar"); // also: should have nested exception Throwable t = e.getCause(); + if (t == null) { + fail("Should have assigned cause for: ("+e.getClass().getSimpleName()+") "+e); + } assertNotNull(t); assertEquals(IllegalArgumentException.class, t.getClass()); assertEquals("foobar", t.getMessage()); @@ -210,23 +213,27 @@ public void testJackson431() throws Exception assertNotNull(foo); } - // Catch and rethrow exceptions that Creator methods throw + // Catch and re-throw exceptions that Creator methods throw public void testJackson438() throws Exception { + Exception e = null; try { MAPPER.readValue("{ \"name\":\"foobar\" }", BeanFor438.class); fail("Should have failed"); - } catch (Exception e) { - if (!(e instanceof JsonMappingException)) { - fail("Should have received JsonMappingException, caught "+e.getClass().getName()); - } - verifyException(e, "don't like that name"); - // Ok: also, let's ensure root cause is directly linked, without other extra wrapping: - Throwable t = e.getCause(); - assertNotNull(t); - assertEquals(IllegalArgumentException.class, t.getClass()); - verifyException(e, "don't like that name"); + } catch (Exception e0) { + e = e0; + } + if (!(e instanceof JsonMappingException)) { + fail("Should have received JsonMappingException, caught "+e.getClass().getName()); + } + verifyException(e, "don't like that name"); + // Ok: also, let's ensure root cause is directly linked, without other extra wrapping: + Throwable t = e.getCause(); + if (t == null) { + fail("Should have assigned cause for: ("+e.getClass().getSimpleName()+") "+e); } + assertEquals(IllegalArgumentException.class, t.getClass()); + verifyException(e, "don't like that name"); } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestExceptionHandling.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestExceptionHandling.java index 6f235175d5..532aee50e0 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/TestExceptionHandling.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestExceptionHandling.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.exc.InputMismatchException; import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; /** @@ -56,7 +57,7 @@ public void testExceptionWithEmpty() throws Exception Object result = mapper.readValue(" ", Object.class); fail("Expected an exception, but got result value: "+result); } catch (Exception e) { - verifyException(e, JsonMappingException.class, "No content"); + verifyException(e, InputMismatchException.class, "No content"); } } @@ -80,8 +81,7 @@ public void testExceptionWithIncomplete() } } - public void testExceptionWithEOF() - throws Exception + public void testExceptionWithEOF() throws Exception { StringReader r = new StringReader(" 3"); JsonFactory f = new JsonFactory(); @@ -96,7 +96,7 @@ public void testExceptionWithEOF() I = mapper.readValue(jp, Integer.class); fail("Should have gotten an exception"); } catch (IOException e) { - verifyException(e, JsonMappingException.class, "No content"); + verifyException(e, InputMismatchException.class, "No content"); } // also: should have no current token after end-of-input JsonToken t = jp.getCurrentToken(); diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/TestJsonSerialize.java b/src/test/java/com/fasterxml/jackson/databind/ser/TestJsonSerialize.java index 01cabf2f1f..483ccb2284 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/TestJsonSerialize.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/TestJsonSerialize.java @@ -148,6 +148,7 @@ public void testBrokenAnnotation() throws Exception { try { serializeAsString(MAPPER, new BrokenClass()); + fail("Should not succeed"); } catch (Exception e) { verifyException(e, "types not related"); }