Skip to content

Commit

Permalink
Merge branch '2.19' into 2.17
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder authored Nov 5, 2024
2 parents ea24d97 + 5d2019b commit 21356c7
Show file tree
Hide file tree
Showing 23 changed files with 532 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cifuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
dry-run: false
language: jvm
- name: Upload Crash
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
4 changes: 2 additions & 2 deletions .github/workflows/dep_build_v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
env:
JAVA_OPTS: "-XX:+TieredCompilation -XX:TieredStopAtLevel=1"
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up JDK
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
with:
distribution: 'temurin'
java-version: ${{ matrix.java_version }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dep_build_v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
env:
JAVA_OPTS: "-XX:+TieredCompilation -XX:TieredStopAtLevel=1"
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: master
- name: Set up JDK
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
with:
distribution: 'temurin'
java-version: ${{ matrix.java_version }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ jobs:
env:
JAVA_OPTS: "-XX:+TieredCompilation -XX:TieredStopAtLevel=1"
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up JDK
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
with:
distribution: 'temurin'
java-version: ${{ matrix.java_version }}
Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
run: ./mvnw -B -q -ff -ntp test
- name: Publish code coverage
if: ${{ github.event_name != 'pull_request' && matrix.release_build }}
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./target/site/jacoco/jacoco.xml
Expand Down
15 changes: 14 additions & 1 deletion release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ Project: jackson-databind
#4676: Support other enum naming strategies than camelCase
(requested by @hajdamak)
(contributed by Lars B)
#4680: Custom key deserialiser registered for `Object.class` in nested
Map object is ignored when Map key type not defined
(reported by @devdanylo)
(fix by Joo-Hyuk K)
#4773: `SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS` should not apply to Maps
with uncomparable keys
(requested by @nathanukey)
(fix by Joo-Hyuk K)

2.18.2 (not yet released)

#4733: Wrong serialization of Type Ids for certain types of Enum values
(reported by @nlisker)

2.18.1 (28-Oct-2024)

Expand Down Expand Up @@ -120,7 +133,7 @@ Project: jackson-databind
#4709: Add `JacksonCollectors` with `toArrayNode()` implementation
(contributed by @rikkarth)
2.17.3 (not yet released)
2.17.3 (01-Nov-2024)
#4718: Should not fail on trying to serialize `java.time.DateTimeException`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1399,14 +1399,14 @@ public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated

/**
* Method called to check if introspector can find a Creator it considers
* the "Default Creator": Creator to use as the primary, when no Creator has
* the "Primary Creator": Creator to use as the primary one, when no Creator has
* explicit annotation ({@link #findCreatorAnnotation} returns {@code null}).
* Examples of default creators include the canonical constructor defined by
* Java Records; "Data" classes by frameworks
* like Lombok and JVM languages like Kotlin and Scala (case classes) also have
* similar concepts.
* If introspector can determine that one of given {@link PotentialCreator}s should
* be considered the default, it should return it; if not, should return {@code null}.
* be considered the primary, it should return it; if not, should return {@code null}.
* Note that core databind functionality may call this method even in the presence of
* explicitly annotated creators; and may or may not use Creator returned depending
* on other criteria.
Expand All @@ -1416,6 +1416,11 @@ public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated
*<p>
* NOTE: method is NOT called for Java Record types; selection of the canonical constructor
* as the Primary creator is handled directly by {@link POJOPropertiesCollector}
*<p>
* NOTE: naming of this method is unfortunately inconsistent in that "default Creator"
* has other meanings than "primary Creator" -- in other places Jackson code
* refers to no-arguments Constructors as "default Creators". So this method
* ought to have been named {@code findPrimaryCreator()}.
*
* @param config Configuration settings in effect (for deserialization)
* @param valueClass Class being instantiated; defines Creators passed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public enum SerializationFeature implements ConfigFeature
* {@link java.util.Calendar} which will always use timezone Calendar value has).
* Setting is also ignored by Joda date/time values.
*<p>
* Featured is enabled by default for backwards-compatibility purposes (in
* Feature is enabled by default for backwards-compatibility purposes (in
* Jackson 2.12 override was always done if there was explicitly defined timezone).
*
* @since 2.13
Expand Down Expand Up @@ -434,6 +434,23 @@ public enum SerializationFeature implements ConfigFeature
*/
ORDER_MAP_ENTRIES_BY_KEYS(false),

/**
* Feature that determines whether to intentionally fail when the mapper attempts to
* order map entries with incomparable keys by accessing the first key of the map.
* So depending on the Map implementation, this may not be the same key every time.
* <p>
* If enabled, will simply fail by throwing an exception.
* If disabled, will not throw an exception and instead simply return the original map.
* <p>
* Note that this feature will apply only when configured to order map entries by keys, either
* through annotation or enabling {@link #ORDER_MAP_ENTRIES_BY_KEYS}.
* <p>
* Feature is enabled by default and will default false in Jackson 3 and later.
*
* @since 2.19
*/
FAIL_ON_ORDER_MAP_BY_INCOMPARABLE_KEY(true),

/*
/******************************************************
/* Other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ public ValueInstantiator constructValueInstantiator(DeserializationContext ctxt)
* it with data. Default creator is only used if no other creators are
* indicated.
*
* @param creator
* Creator method; no-arguments constructor or static factory
* method.
* @param creator Creator method; no-arguments constructor or factory method.
*/
public void setDefaultCreator(AnnotatedWithParams creator) {
_creators[C_DEFAULT] = _fixAccess(creator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ public class UntypedObjectDeserializer

protected JsonDeserializer<Object> _numberDeserializer;

/**
* Object.class may also have custom key deserializer
*
* @since 2.19
*/
private KeyDeserializer _customKeyDeserializer;

/**
* If {@link java.util.List} has been mapped to non-default implementation,
* we'll store type here
Expand All @@ -73,7 +80,7 @@ public class UntypedObjectDeserializer
*/
@Deprecated
public UntypedObjectDeserializer() {
this(null, null);
this(null, (JavaType) null);
}

public UntypedObjectDeserializer(JavaType listType, JavaType mapType) {
Expand All @@ -95,6 +102,7 @@ public UntypedObjectDeserializer(UntypedObjectDeserializer base,
_numberDeserializer = (JsonDeserializer<Object>) numberDeser;
_listType = base._listType;
_mapType = base._mapType;
_customKeyDeserializer = base._customKeyDeserializer;
_nonMerging = base._nonMerging;
}

Expand All @@ -111,9 +119,27 @@ protected UntypedObjectDeserializer(UntypedObjectDeserializer base,
_numberDeserializer = base._numberDeserializer;
_listType = base._listType;
_mapType = base._mapType;
_customKeyDeserializer = base._customKeyDeserializer;
_nonMerging = nonMerging;
}

/**
* @since 2.19
*/
protected UntypedObjectDeserializer(UntypedObjectDeserializer base,
KeyDeserializer keyDeser)
{
super(Object.class);
_mapDeserializer = base._mapDeserializer;
_listDeserializer = base._listDeserializer;
_stringDeserializer = base._stringDeserializer;
_numberDeserializer = base._numberDeserializer;
_listType = base._listType;
_mapType = base._mapType;
_nonMerging = base._nonMerging;
_customKeyDeserializer = keyDeser;
}

/*
/**********************************************************
/* Initialization
Expand Down Expand Up @@ -190,19 +216,32 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
// 14-Jun-2017, tatu: [databind#1625]: may want to block merging, for root value
boolean preventMerge = (property == null)
&& Boolean.FALSE.equals(ctxt.getConfig().getDefaultMergeable(Object.class));
// Since 2.19, 31-Aug-2024: [databind#4680] Allow custom key deserializer for Object.class
KeyDeserializer customKeyDeser = ctxt.findKeyDeserializer(ctxt.constructType(Object.class), property);
// but make sure to ignore standard/default key deserializer (perf optimization)
if (customKeyDeser != null) {
if (ClassUtil.isJacksonStdImpl(customKeyDeser)) {
customKeyDeser = null;
}
}
// 20-Apr-2014, tatu: If nothing custom, let's use "vanilla" instance,
// simpler and can avoid some of delegation
if ((_stringDeserializer == null) && (_numberDeserializer == null)
&& (_mapDeserializer == null) && (_listDeserializer == null)
&& (customKeyDeser == null) // [databind#4680] Since 2.19 : Allow custom key deserializer for Object.class
&& getClass() == UntypedObjectDeserializer.class) {
return UntypedObjectDeserializerNR.instance(preventMerge);
}

UntypedObjectDeserializer deser = this;
if (preventMerge != _nonMerging) {
return new UntypedObjectDeserializer(this, preventMerge);
deser = new UntypedObjectDeserializer(deser, preventMerge);
}

return this;
// [databind#4680] Since 2.19 : Allow custom key deserializer for Object.class
if (customKeyDeser != null) {
deser = new UntypedObjectDeserializer(deser, customKeyDeser);
}
return deser;
}

/*
Expand Down Expand Up @@ -496,6 +535,7 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
// empty map might work; but caller may want to modify... so better just give small modifiable
return new LinkedHashMap<>(2);
}
key1 = _customDeserializeKey(key1, ctxt);
// minor optimization; let's handle 1 and 2 entry cases separately
// 24-Mar-2015, tatu: Ideally, could use one of 'nextXxx()' methods, but for
// that we'd need new method(s) in JsonDeserializer. So not quite yet.
Expand All @@ -508,6 +548,8 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
result.put(key1, value1);
return result;
}
key2 = _customDeserializeKey(key2, ctxt);

p.nextToken();
Object value2 = deserialize(p, ctxt);

Expand All @@ -521,6 +563,8 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
}
return result;
}
key = _customDeserializeKey(key, ctxt);

// And then the general case; default map size is 16
LinkedHashMap<String, Object> result = new LinkedHashMap<>();
result.put(key1, value1);
Expand All @@ -535,9 +579,9 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
final Object oldValue = result.put(key, newValue);
if (oldValue != null) {
return _mapObjectWithDups(p, ctxt, result, key, oldValue, newValue,
p.nextFieldName());
_customDeserializeNullableKey(p.nextFieldName(), ctxt));
}
} while ((key = p.nextFieldName()) != null);
} while ((key = _customDeserializeNullableKey(p.nextFieldName(), ctxt)) != null);
return result;
}

Expand All @@ -559,12 +603,44 @@ protected Object _mapObjectWithDups(JsonParser p, DeserializationContext ctxt,
if ((oldValue != null) && squashDups) {
_squashDups(result, key, oldValue, newValue);
}
nextKey = p.nextFieldName();
nextKey = _customDeserializeNullableKey(p.nextFieldName(), ctxt);
}

return result;
}

/**
* Helper function to allow custom key deserialization without null handling.
* Similar to {@link #_customDeserializeNullableKey(String, DeserializationContext)}, but
* null handling is done by the caller.
*
* @returns Custom-deserialized key if both custom key deserializer is set.
* Otherwise the original key.
*/
private final String _customDeserializeKey(String key, DeserializationContext ctxt) throws IOException {
if (_customKeyDeserializer != null) {
return (String) _customKeyDeserializer.deserializeKey(key, ctxt);
}
return key;
}

/**
* Helper function to allow custom key deserialization with null handling.
* Similar to {@link #_customDeserializeKey(String, DeserializationContext)}, but instead
* only returns custom-deserialized key if key is not null.
*
* @returns Custom-deserialized key if both custom key deserializer is set and key is not null.
* Otherwise the original key.
*/
private final String _customDeserializeNullableKey(String key, DeserializationContext ctxt) throws IOException {
if (_customKeyDeserializer != null) {
if (key != null) {
return (String) _customKeyDeserializer.deserializeKey(key, ctxt);
}
}
return key;
}

@SuppressWarnings("unchecked")
private void _squashDups(final Map<String, Object> result, String key,
Object oldValue, Object newValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,13 +739,13 @@ public PotentialCreator findDefaultCreator(MapperConfig<?> config,
AnnotatedClass valueClass,
List<PotentialCreator> declaredConstructors,
List<PotentialCreator> declaredFactories) {
PotentialCreator defCtor = _primary.findDefaultCreator(config,
PotentialCreator primaryCtor = _primary.findDefaultCreator(config,
valueClass, declaredConstructors, declaredFactories);
if (defCtor == null) {
defCtor = _secondary.findDefaultCreator(config,
if (primaryCtor == null) {
primaryCtor = _secondary.findDefaultCreator(config,
valueClass, declaredConstructors, declaredFactories);
}
return defCtor;
return primaryCtor;
}

/*
Expand Down
Loading

0 comments on commit 21356c7

Please sign in to comment.