Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Cannot customize String deserialization behavior #59

Closed
brianwyantora opened this issue Sep 25, 2015 · 7 comments
Closed

Cannot customize String deserialization behavior #59

brianwyantora opened this issue Sep 25, 2015 · 7 comments
Milestone

Comments

@brianwyantora
Copy link

I have a use case where we use CharacterEscapes to encode a few characters serialized with Jackson. The other side of the coin is that we've long used a simple JsonDeserializer to unencode these same characters. Basically, the intent being that by making an RO into JSON, then converting the JSON back into the RO, there's no changes that occur during the round trip.

Let's be more specific. I want to get the following test to pass. Is there any way that I can accomplish this?

@Test
public void ensureSimpleROCanGetCreatedWithUnescapedJSON() throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = // ...;
    module.addDeserializer(String.class, ...);
    module.addValueInstantiator(String.class, ...);
    mapper.registerModule(new AfterburnerModule());
    mapper.registerModule(module);

    String jsonObject = "{\"field\": \"value & value\"}";
    SimpleRO parsedRO = mapper.readValue(jsonObject, SimpleRO.class);
    Assert.assertEquals("value & value", parsedRO.field);
}

private static class SimpleRO {
    public String field;
}

Both the JsonDeserializer I have configured (implementing public String deserialize(JsonParser parser, DeserializationContext context) throws IOException) and the StdValueInstantiator I have configured (implementing public Object createFromString(DeserializationContext ctxt, String value) throws IOException) pass the strings through a method which does, basically return Pattern.compile("&").matcher(string).replaceAll("&");.

Without afterburner, this test passes. With, it fails. Any ideas?

@cowtowncoder
Copy link
Member

Since one major area of optimizations Afterburner does is to "inline" handling of simple datatypes, including Strings, it is possible that override is accidentally removing part of customized handling.
So this is likely a bug.
Is this with version 2.6?

If you could provide a complete test case (like unit test), it should be easy for me to figure out a way to fix this (based on similar problems solved earlier).

@brianwyantora
Copy link
Author

I was originally on jackson/afterburner 2.4.2, saw this issue, bumped to 2.6.2, issue remained. So yes, 2.6.2.

Complete repro JUnit test:

import java.io.IOException;

import org.junit.Assert;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;

public class JacksonTestIssue59 {
    @Test
    public void ensureSimpleROCanGetCreatedWithUnescapedJSON() throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule("module", new Version(0, 0, 0, "", "", ""));
        module.addDeserializer(String.class, new JsonDeserializer<String>() {

            @Override
            public String deserialize(JsonParser p, DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {
                return p.getText().replaceAll("&amp;", "&");
            }

        });
        mapper.registerModule(new AfterburnerModule());
        mapper.registerModule(module);

        String jsonObject = "{\"field\": \"value &amp; value\"}";
        SimpleRO parsedRO = mapper.readValue(jsonObject, SimpleRO.class);
        Assert.assertEquals("value & value", parsedRO.field);
    }

    private static class SimpleRO {
        public String field;
    }
}

I demonstrated by commenting out the line configuring the AfterburnerModule, after which it passed. As written, it fails.

@cowtowncoder
Copy link
Member

Ok I can reproduce this.

Looks like the existing test for non-standard deserializers was only using per-property annotations, not central registration, which is why it did not fail.

Unfortunately this may be a tricky thing to resolve because the code that adds optimized handlers does not have access to DeserializationContext (to be able to see if custom deserializers are registered).

@brianwyantora
Copy link
Author

I can't tell. I don't see any changes you made to fix this, but the issue is marked as closed. Was that just a side effect of your commit message?

@cowtowncoder cowtowncoder reopened this Oct 1, 2015
@cowtowncoder
Copy link
Member

Hmmh, odd. I did not mean to (or think I did) close it... it is definitely an issue that needs to be solved.

cowtowncoder added a commit that referenced this issue Oct 5, 2015
@cowtowncoder cowtowncoder added this to the 2.6.3 milestone Oct 5, 2015
@cowtowncoder
Copy link
Member

Found a way to fix this; not optimal but appears to work. Also fixed a related problem for deserializers. In both cases the issue is that serializer/deserializer is associated at a later point, not during construction (unlike with direct annotations), and needs to be handled after the fact.

@brianwyantora
Copy link
Author

Great. Thanks!

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

No branches or pull requests

2 participants