-
-
Notifications
You must be signed in to change notification settings - Fork 796
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to ignore properties when deserializing. TokenFilter seems broken #700
Comments
First things first: Mix-in, however, should safely ignore field. But your test case above has 2 problems:
So I think it should be possible to make this (mix-in) approach work. Filter case is interesting and I don't know for sure what the issue might be: I would like to have a look if I have time, to see what is causing issues. Also, if you can specify a helper class like:
you can avoid using mix-ins, and simplify code to something like
which might be the simplest way to do it. |
hi, @cowtowncoder, I've updated the test case. package com.alibaba.dapr.serialization.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.filter.FilteringParserDelegate;
import com.fasterxml.jackson.core.filter.TokenFilter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@Ignore
public class IgnorePropertyTest {
private final ObjectMapper mapper = new ObjectMapper().addMixIn(Map.class, MixIn.class);
private final String LONG_INNER_MAP_WITH_AUTO_TYPE = "{\"@type\":\"java.util.LinkedHashMap\",\"111\":{\"@type\":\"java.util.LinkedHashMap\",\"1\":11,\"2\":22}}";
@Test
public void testTokenFilter() throws Exception {
final TokenFilter tokenFilter = new TokenFilter() {
@Override
public TokenFilter includeProperty(String name) {
if ("@type".equals(name)) {
return null;
}
return this;
}
};
JsonParser jsonParser = new FilteringParserDelegate(
mapper.createParser(LONG_INNER_MAP_WITH_AUTO_TYPE),
tokenFilter,
TokenFilter.Inclusion.INCLUDE_ALL_AND_PATH,
true);
Map<Long, Map<Long, Long>> data = mapper.readValue(jsonParser, new TypeReference<Map<Long, Map<Long, Long>>>() {});
check(data);
}
@Test
public void testReader() throws Exception {
ObjectReader reader = mapper.readerFor(new TypeReference<Map<Long, Map<Long, Long>>>() {});
Map<Long, Map<Long, Long>> data = reader.withoutAttribute("@type").readValue(LONG_INNER_MAP_WITH_AUTO_TYPE);
check(data);
}
@Test
public void testMixin() throws Exception {
Map<Long, Map<Long, Long>> data = mapper.readValue(LONG_INNER_MAP_WITH_AUTO_TYPE, new TypeReference<Map<Long, Map<Long, Long>>>() {});
check(data);
}
@Test
public void testCustomMap() throws Exception {
Map data = mapper.readValue(LONG_INNER_MAP_WITH_AUTO_TYPE, new TypeReference<MyLongMap>() {});
check(data);
}
@JsonIgnoreProperties({"@type"})
public static class MyLongMap extends HashMap<Long, MyInnerLongMap> {
}
@JsonIgnoreProperties({"@type"})
public static class MyInnerLongMap extends HashMap<Long, Long> {
}
@JsonIgnoreProperties({"@type"})
private static abstract class MixIn {
}
private void check(Map<Long, Map<Long, Long>> data) {
assertEquals(1, data.size());
assertEquals(2, data.get(111L).size());
assertEquals(11L, (long)data.get(111L).get(1L));
assertEquals(22L, (long)data.get(111L).get(2L));
}
} |
I've achieved my goal by writing my own filtering parser. package com.alibaba.dapr.serialization.json;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.util.JsonParserDelegate;
import java.io.IOException;
import static com.fasterxml.jackson.core.JsonTokenId.ID_FIELD_NAME;
/**
* Ignores com.alibaba.fastjson.JSON#DEFAULT_TYPE_KEY.
* Because {@link com.fasterxml.jackson.core.filter.FilteringParserDelegate} is broken at the moment,
* we have to write our own simple filtering parser.
* @author zuojie
*/
public class TypeFieldFilteringParserDelegate extends JsonParserDelegate {
public TypeFieldFilteringParserDelegate(JsonParser d) {
super(d);
}
public JsonToken nextToken() throws IOException {
JsonToken t = delegate.nextToken();
if (t == null) {
return null;
}
if (t.id() == ID_FIELD_NAME) {
final String name = delegate.getCurrentName();
if ("@type".equals(name)) {
delegate.nextToken();
delegate.skipChildren();
return delegate.nextToken();
}
}
return t;
}
} package com.alibaba.dapr.serialization.json;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.filter.FilteringParserDelegate;
import com.fasterxml.jackson.core.filter.TokenFilter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@Ignore
public class IgnorePropertyTest {
private final ObjectMapper mapper = new ObjectMapper().addMixIn(Map.class, MixIn.class);
private final String LONG_INNER_MAP_WITH_AUTO_TYPE = "{\"@type\":\"java.util.LinkedHashMap\",\"111\":{\"@type\":\"java.util.LinkedHashMap\",\"1\":11,\"2\":22}}";
@Test
public void testTokenFilter() throws Exception {
final TokenFilter tokenFilter = new TokenFilter() {
@Override
public TokenFilter includeProperty(String name) {
if ("@type".equals(name)) {
return null;
}
return this;
}
};
JsonParser jsonParser = new FilteringParserDelegate(
mapper.createParser(LONG_INNER_MAP_WITH_AUTO_TYPE),
tokenFilter,
TokenFilter.Inclusion.INCLUDE_ALL_AND_PATH,
true);
Map<Long, Map<Long, Long>> data = mapper.readValue(jsonParser, new TypeReference<Map<Long, Map<Long, Long>>>() {});
check(data);
}
@Test
public void testReader() throws Exception {
ObjectReader reader = mapper.readerFor(new TypeReference<Map<Long, Map<Long, Long>>>() {});
Map<Long, Map<Long, Long>> data = reader.withoutAttribute("@type").readValue(LONG_INNER_MAP_WITH_AUTO_TYPE);
check(data);
}
@Test
public void testMixin() throws Exception {
Map<Long, Map<Long, Long>> data = mapper.readValue(LONG_INNER_MAP_WITH_AUTO_TYPE, new TypeReference<Map<Long, Map<Long, Long>>>() {});
check(data);
}
@Test
public void testCustomMap() throws Exception {
Map data = mapper.readValue(LONG_INNER_MAP_WITH_AUTO_TYPE, new TypeReference<MyLongMap>() {});
check(data);
}
@Test
public void testCustomFilteringParserDelegate() throws Exception {
JsonParser jsonParser = new TypeFieldFilteringParserDelegate(mapper.createParser(LONG_INNER_MAP_WITH_AUTO_TYPE));
Map data = mapper.readValue(jsonParser, new TypeReference<MyLongMap>() {});
check(data);
}
@JsonIgnoreProperties({"@type"})
public static class MyLongMap extends HashMap<Long, MyInnerLongMap> {
}
@JsonIgnoreProperties({"@type"})
public static class MyInnerLongMap extends HashMap<Long, Long> {
}
@JsonIgnoreProperties({"@type"})
private static abstract class MixIn {
}
private void check(Map<Long, Map<Long, Long>> data) {
assertEquals(1, data.size());
assertEquals(2, data.get(111L).size());
assertEquals(11L, (long)data.get(111L).get(1L));
assertEquals(22L, (long)data.get(111L).get(2L));
}
} testCustomFilteringParserDelegate finally works. |
@xiazuojie thank you for sharing your solution. I hope to have a look at your original case to see why ignoral does not work, but at least you have a work-around. |
I am able to reproduce this with even simpler case:
which produces erroneous stream of
(that is, missing value). |
Phew! Was able to figure out issues: turns out there was a code path commented out (for reasons unknown to me) responsible for the main issue -- but also, at databind level there was a minor quirk in Map deserializer as well. Fix will be in 2.13.0-rc2 (if one published) or final 2.13.0 (if no more release candidates). Thank you @xiazuojie for reporting this problem! |
We have the following JSON generated by another JSON library that includes property
@type
to indicate value types. We want Jackson to ignore@type
properties (both root and inner ones) when deserializing the data toMap<Long, Map<Long, Long>>
.What we have tried so far:
ObjectReader.withoutAttribute("@type")
ObjectMapper.addMixIn
TokenFilter
None of the above gets what we want.
The closest result we've got is by using
TokenFilter
. However, there's always something broker no matter what combination of TokenFilter options we choose:TokenFilter#includeProperty
returningthis
orTokenFilter#INCLUDE_ALL
TokenFilter.Inclusion
enums forFilteringParserDelegate#_inclusion
FilteringParserDelegate#_allowMultipleMatches
true or falseIt seems TokenFilter is broken. The following is our test case.
Jackson version: 2.12.3
The text was updated successfully, but these errors were encountered: