Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f3d38b0
...
JooHyukKim Sep 2, 2024
e832d13
Improve test doc
JooHyukKim Sep 2, 2024
06f8b83
Merge branch '2.18' into fix4680
cowtowncoder Sep 5, 2024
a1fe9cc
Add check if is default key-deserializer
JooHyukKim Sep 5, 2024
9222ade
Improve validation to check if custom-key-deserializer is not null
JooHyukKim Sep 5, 2024
6e04144
Merge branch '2.18' into fix4680
cowtowncoder Sep 12, 2024
149180c
Merge branch '2.18' into fix4680
cowtowncoder Sep 20, 2024
03b365a
Minor renaming, tweaks
cowtowncoder Sep 20, 2024
f91f0a3
Merge branch '2.18' into fix4680
cowtowncoder Sep 20, 2024
8976fef
Remove dup test class
cowtowncoder Sep 20, 2024
e80b337
Minor streamlining
cowtowncoder Sep 20, 2024
1f7dfbc
Add and cover at least 5 keys cases
JooHyukKim Sep 21, 2024
874dd82
Update doc
JooHyukKim Sep 21, 2024
39aa9a1
Merge branch '2.18' into fix4680
cowtowncoder Sep 29, 2024
672c69e
Merge remote-tracking branch 'upstream/2.19' into fix4680
JooHyukKim Sep 29, 2024
2792f28
Add version note
JooHyukKim Sep 29, 2024
83af378
Add "since" to where needed
JooHyukKim Sep 29, 2024
c09b191
Merge branch '2.19' into fix4680
cowtowncoder Oct 2, 2024
517edba
tiny tweaks
cowtowncoder Oct 2, 2024
ef0e18c
some last (?) tweaks
cowtowncoder Oct 2, 2024
1a0cdbf
Add some JavaDoc
JooHyukKim Oct 2, 2024
212bc64
Add comments
JooHyukKim Oct 2, 2024
3c35bcd
Merge branch '2.19' into fix4680
cowtowncoder Oct 3, 2024
f58cdd6
Merge branch 'fix4680' of github.com:JooHyukKim/jackson-databind into…
cowtowncoder Oct 3, 2024
d48f5f6
Merge branch '2.19' into fix4680
cowtowncoder Oct 3, 2024
2989044
Merge branch '2.19' into fix4680
cowtowncoder Oct 3, 2024
b32f234
Merge branch '2.19' into fix4680
JooHyukKim Oct 9, 2024
95e7887
Merge branch '2.19' into fix4680
cowtowncoder Oct 16, 2024
cabc459
Merge branch '2.19' into fix4680
JooHyukKim Nov 1, 2024
c09e88c
Clean up
JooHyukKim Nov 1, 2024
abe4e17
Merge branch '2.19' into fix4680
cowtowncoder Nov 1, 2024
9f99e87
Merge branch '2.19' into fix4680
cowtowncoder Nov 5, 2024
498c354
Minor javadoc fix
cowtowncoder Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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 @@ -74,7 +81,7 @@ public class UntypedObjectDeserializer
*/
@Deprecated
public UntypedObjectDeserializer() {
this(null, null);
this(null, (JavaType) null);
}

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

Expand All @@ -112,9 +120,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 @@ -191,19 +217,31 @@ 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));
// 31-Aug-2024: [databind#4680] Allow custom key deserializer for Object.class deserialization
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)
&& 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;
if (customKeyDeser != null) {
deser = new UntypedObjectDeserializer(deser, customKeyDeser);
}
return deser;
}

/*
Expand Down Expand Up @@ -496,6 +534,8 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
if (key1 == null) {
// empty map might work; but caller may want to modify... so better just give small modifiable
return new LinkedHashMap<>(2);
} else if (_customKeyDeserializer != null) {
key1 = (String) _customKeyDeserializer.deserializeKey(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
Expand All @@ -508,6 +548,8 @@ protected Object mapObject(JsonParser p, DeserializationContext ctxt) throws IOE
LinkedHashMap<String, Object> result = new LinkedHashMap<>(2);
result.put(key1, value1);
return result;
} else if (_customKeyDeserializer != null) {
key2 = (String) _customKeyDeserializer.deserializeKey(key2, ctxt);
Copy link
Member

Choose a reason for hiding this comment

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

@JooHyukKim I think same check needed for 2 cases further down too?
(and test should check that first 5 keys per level get custom deserialized as well)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, seems like it. Will do

Copy link
Member Author

Choose a reason for hiding this comment

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

Applied ur review and did minor plummeting (with a new helper function) via 1f7dfbc. Thanks!

}
p.nextToken();
Object value2 = deserialize(p, ctxt);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
package com.fasterxml.jackson.databind.tofix;
package com.fasterxml.jackson.databind.deser;

import java.util.Map;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

// [databind#4680] Custom key deserialiser registered for `Object.class` is ignored on nested JSON
public class CustomObjectKeyDeserializer4680Test
public class CustomKeyDeserializer4680Test
{

@JacksonTestFailureExpected
// [databind#4680]
@Test
void testCustomKeyDeserializer()
throws Exception
{
void customKeyDeserializerShouldBeUsedWhenTypeNotDefined() throws Exception {
// GIVEN
String json =
"{\n" +
" \"name*\": \"Erik\",\n" +
" \"address*\": {\n" +
" \"city*\": {\n" +
" \"id*\": 1,\n" +
" \"name*\": \"Berlin\"\n" +
" },\n" +
" \"street*\": \"Elvirastr\"\n" +
" }\n" +
" }";
String json = "{\n" +
" \"name*\": \"Erik\",\n" +
" \"address*\": {\n" +
" \"city*\": {\n" +
" \"id*\": 1,\n" +
" \"name*\": \"Berlin\"\n" +
" },\n" +
" \"street*\": \"Elvirastr\"\n" +
" }\n" +
" }";

SimpleModule keySanitizationModule = new SimpleModule("key-sanitization");
keySanitizationModule.addKeyDeserializer(String.class, new KeyDeserializer() {
Expand Down Expand Up @@ -69,4 +64,4 @@ public Object deserializeKey(String key, DeserializationContext ctxt) {
Assertions.assertEquals("Berlin", cityMap.get("name_"));
}

}
}