Skip to content
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

Jackson 2.5.0. NullSerializer for MapProperty failing (no serializeWithType) #691

Closed
Antibrumm opened this issue Jan 29, 2015 · 7 comments
Closed
Milestone

Comments

@Antibrumm
Copy link

I'm not sure if that's a bug our if it comes because of some configuration of mine.

In version 2.5.0 I had to fix the NullSerializer by implementing the serializeWithType method to call jgen.writeNull() as the default throws an UnsupportedOperationException.

I saw that the BeanPropertyWriter is calling serialize but MapProperty is calling serializeWithType.

Here's the stacktrace:

FixedNullSerializer.serializeWithType(Object, JsonGenerator, SerializerProvider, TypeSerializer) line: 26   
MapProperty.serializeAsField(Object, JsonGenerator, SerializerProvider) line: 102   
AntPathPropertyFilter.serializeAsField(Object, JsonGenerator, SerializerProvider, PropertyWriter) line: 157 
MapSerializer.serializeFilteredFields(Map<?,?>, JsonGenerator, SerializerProvider, PropertyFilter, Object) line: 731    
MapSerializer.serializeWithType(Map<?,?>, JsonGenerator, SerializerProvider, TypeSerializer) line: 493  
MapSerializer.serializeWithType(Object, JsonGenerator, SerializerProvider, TypeSerializer) line: 29 
TypeWrappedSerializer.serialize(Object, JsonGenerator, SerializerProvider) line: 32 
DefaultSerializerProvider$Impl(DefaultSerializerProvider).serializeValue(JsonGenerator, Object) line: 129   
ObjectMapper.writeValue(JsonGenerator, Object) line: 2238   
Jackson2Helper.writeFiltered(Object, String...) line: 51    
@cowtowncoder
Copy link
Member

A unit test would help here, as the problem may be in multiple places -- off-hand, I wouldn't think that method should ever be called on that serializer. Which is why exception is thrown, as an assertion.
I would not want to mask the underlying problem for such case.

On the other hand it is possible that there could be a valid exception to this as well. A test could show either way. :)

@Antibrumm
Copy link
Author

Here's a test case + a fixed test.

I just discovered that the NULL field is serialized twice once the exception throwing is fixed.

Output

NORMAL: {"id":"Test","NULL":null}
FIXED: {"@c":".HashMap","id":"Test","NULL":null,"NULL":null}

Tests

public class NullFailTest {

    @JsonTypeInfo(use = Id.MINIMAL_CLASS)
    public static class Mixin {

    }

    @Test(expected = JsonMappingException.class)
    public void testNullJsonMappingException() throws JsonProcessingException {
        Map<String, String> map = new HashMap<String, String>();
        map.put("id", "Test");
        map.put("NULL", null);

        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println("NORMAL: " + objectMapper.writeValueAsString(map));

        objectMapper = new ObjectMapper();
        objectMapper.addMixIn(Object.class, Mixin.class);

        System.out.println("TYPED (throwing exception): " + objectMapper.writeValueAsString(map));

    }

    @Test
    public void testNullFixed() throws JsonProcessingException {

        Map<String, String> map = new HashMap<String, String>();
        map.put("id", "Test");
        map.put("NULL", null);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.addMixIn(Object.class, Mixin.class);
        objectMapper.getSerializerProvider().setNullValueSerializer(FixedNullSerializer.instance);
        System.out.println("FIXED (but serializing NULL field twice): " + objectMapper.writeValueAsString(map));
    }

    public static class FixedNullSerializer extends StdSerializer<Object> {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        public final static FixedNullSerializer instance = new FixedNullSerializer();

        @Override
        public void serializeWithType(Object value, JsonGenerator jgen, SerializerProvider serializers,
            TypeSerializer typeSer) throws IOException {
            jgen.writeNull();
        }

        private FixedNullSerializer() {
            super(Object.class);
        }

        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeNull();
        }

        @Override
        public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException {
            return createSchemaNode("null");
        }

        @Override
        public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
                throws JsonMappingException {
            visitor.expectNullFormat(typeHint);
        }
    }
}

@cowtowncoder
Copy link
Member

This may well be a bug due to refactorings in 2.5.0, which try to ensure that all handlers are properly used.
Thank you for the test!

@cowtowncoder
Copy link
Member

Unfortunately I am not able to reproduce the failure with above test case. Looking at the original stack trace, it seems like there is something additional, like JSON Filter in use? If so, could you show how it is added, to reproduce the exception?

cowtowncoder added a commit that referenced this issue Feb 6, 2015
@Antibrumm
Copy link
Author

Strange. Did you run it against 2.5.0 or already a new snapshot?

I ran it through the antpath filter maven project (jackson 2.5.0). I thought the test case should be independant. As far as I remember the objectMapper together with the typeid generator raised the issue.
I can do another run.

@cowtowncoder
Copy link
Member

Ah. Running the test exactly as shown and with 2.5.0 branch does reproduce it. So my simplified reproduction had some issue... Ok. Back to testing.

cowtowncoder added a commit that referenced this issue Feb 7, 2015
@cowtowncoder cowtowncoder added this to the 2.5.2 milestone Feb 7, 2015
@cowtowncoder
Copy link
Member

Ok I was able to follow the problem, and you were exactly right here regarding the root cause.

And the reason why my test failed to catch this was somewhat interesting: since I did not use a mix-in, @JsonTypeInfo when added to a Map type applies to values. However, when added to base java.lang.Object, type can not be detected to be a container type (Map or Collection), and thereby it does apply to type itself, not contents.

I did add serializeWithType(), as well as handle duplicate writing of null. I think this was a 2.5 regression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants