jackson-databind
jackson-databind copied to clipboard
javax.mail.internet.InternetAddress string-argument constructor not being recognized.
Describe the bug
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of
javax.mail.internet.InternetAddress (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('[email protected]')
ValueInstantiator inst = this.getValueInstantiator();
Class<?> rawTargetType = this.handledType();
String value = p.getValueAsString();
if (inst != null && inst.canCreateFromString()) {
return inst.createFromString(ctxt, value);
} else {
CoercionAction act;
if (value.isEmpty()) {
act = ctxt.findCoercionAction(this.logicalType(), rawTargetType, CoercionInputShape.EmptyString);
return this._deserializeFromEmptyString(p, ctxt, act, rawTargetType, "empty String (\"\")");
} else if (_isBlank(value)) {
act = ctxt.findCoercionFromBlankString(this.logicalType(), rawTargetType, CoercionAction.Fail);
return this._deserializeFromEmptyString(p, ctxt, act, rawTargetType, "blank String (all whitespace)");
} else {
if (inst != null) {
value = value.trim();
if (inst.canCreateFromInt() && ctxt.findCoercionAction(LogicalType.Integer, Integer.class, CoercionInputShape.String) == CoercionAction.TryConvert) {
return inst.createFromInt(ctxt, this._parseIntPrimitive(ctxt, value));
}
if (inst.canCreateFromLong() && ctxt.findCoercionAction(LogicalType.Integer, Long.class, CoercionInputShape.String) == CoercionAction.TryConvert) {
return inst.createFromLong(ctxt, this._parseLongPrimitive(ctxt, value));
}
if (inst.canCreateFromBoolean() && ctxt.findCoercionAction(LogicalType.Boolean, Boolean.class, CoercionInputShape.String) == CoercionAction.TryConvert) {
String str = value.trim();
if ("true".equals(str)) {
return inst.createFromBoolean(ctxt, true);
}
if ("false".equals(str)) {
return inst.createFromBoolean(ctxt, false);
}
}
}
return ctxt.handleMissingInstantiator(rawTargetType, inst, ctxt.getParser(), "no String-argument constructor/factory method to deserialize from String value ('%s')", new Object[]{value});
}
}
}
In the above code, default behaviour is throwing MissingInstantiator error, when canCreateFromString
resolves to false.
We see the behaviour has changed for 2.6.7
databind version to 2.13.2.2
databind version when canCreateFromString
resolves to false.
In 2.6.7, the default behaviour is as below:
if (this._objectIdReader != null) {
return this.deserializeFromObjectId(p, ctxt);
} else if (this._delegateDeserializer != null && !this._valueInstantiator.canCreateFromString()) {
Object bean = this._valueInstantiator.createUsingDelegate(ctxt, this._delegateDeserializer.deserialize(p, ctxt));
if (this._injectables != null) {
this.injectValues(ctxt, bean);
}
return bean;
} else {
return this._valueInstantiator.createFromString(ctxt, p.getText());
}
}
If canCreateFromString
is false, the default behaviour of createFromString
is execute.
This behaviour change is breaking our application. Is there a workaround for this issue?
Version information
2.13.2.2
To Reproduce If you have a way to reproduce this with:
- javax.mail.internet.InternetAddress being passed as string in JSON data.
- Longer example stored somewhere else (diff repo, snippet), add a link
- Textual explanation: include here
Expected behavior The original behaviour should work, for backward compatibility.
Additional context
https://github.com/FasterXML/jackson-databind/issues/1318 https://github.com/FasterXML/jackson-dataformat-xml/issues/254
This could be a regression, or could be a fix if constructor was detected earlier for cases it should not have been. I do not off-hand know what the change here would have been.
This could be related to security concerns on auto-detecting constructors from java.*
/ javax.*
packages, although I do not remember exact details of possible changes.
But one quick question: which Constructor of javax.mail.internet.InternetAddress
you think should be auto-detected, based on looking at Javadocs?
Also: it might be useful to know more specifically minor version in which change was observed, assuming this is easy to do.
Ok, I think this was due to what I described above, so type was "accidentally" supported. With 2.12 and beyond this does not (and should not) work -- JDK types need explicit support. Partly this is wrt security (to avoid possible unintended "gadget" types), and partly since later JDKs are unlikely to allow access to these constructors via module system without user configuration. So it is better to have explicit support.
Now, it does not look like this type is part of core JDK even in JDK 8 (and definitely not in later modular JDKs). So it would need to be provided by a module, for whichever API package it is part of.
I will keep this open for now but will annotate with "wont-fix" since there is no plan to change behavior of core jackson-databind
itself here.