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

FilteringGeneratorDelegate does not handle writeString(Reader, int) #609

Closed
vy opened this issue Mar 16, 2020 · 5 comments
Closed

FilteringGeneratorDelegate does not handle writeString(Reader, int) #609

vy opened this issue Mar 16, 2020 · 5 comments

Comments

@vy
Copy link
Contributor

vy commented Mar 16, 2020

I am able to reproduce the following bug using jackson-core-2.10.3:

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate;
import com.fasterxml.jackson.core.filter.TokenFilter;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.assertj.core.api.Assertions;
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;

public class JacksonTest {

    private static class NullExcludingTokenFilter extends TokenFilter {

        private static final NullExcludingTokenFilter INSTANCE =
                new NullExcludingTokenFilter();

        @Override
        public boolean includeNull() {
            return false;
        }

    }

    private static class StringTruncatingGeneratorDelegate
            extends JsonGeneratorDelegate {

        private final int maxStringLength;

        private StringTruncatingGeneratorDelegate(
                JsonGenerator jsonGenerator,
                int maxStringLength) {
            super(jsonGenerator);
            this.maxStringLength = maxStringLength;
        }

        @Override
        public void writeString(String text) throws IOException {
            if (text == null) {
                writeNull();
            } else if (maxStringLength <= 0 || maxStringLength >= text.length()) {
                super.writeString(text);
            } else {
                StringReader textReader = new StringReader(text);
                super.writeString(textReader, maxStringLength);
            }
        }

        @Override
        public void writeFieldName(String name) throws IOException {
            if (maxStringLength <= 0 || maxStringLength >= name.length()) {
                super.writeFieldName(name);
            } else {
                String truncatedName = name.substring(0, maxStringLength);
                super.writeFieldName(truncatedName);
            }
        }

    }

    @Test
    public void test() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonFactory jsonFactory = objectMapper.getFactory();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        JsonGenerator jsonGenerator = jsonFactory.createGenerator(outputStream);
        jsonGenerator = new FilteringGeneratorDelegate(
                jsonGenerator, NullExcludingTokenFilter.INSTANCE, true, true);
        int maxStringLength = 10;
        jsonGenerator = new StringTruncatingGeneratorDelegate(
                jsonGenerator, maxStringLength);
        jsonGenerator.writeStartObject();
        jsonGenerator.writeFieldName("message");
        jsonGenerator.writeString("1234567890!");
        jsonGenerator.writeEndObject();
        jsonGenerator.flush();
        String json = outputStream.toString("US-ASCII");
        Assertions.assertThat(json).isEqualTo("{\"message\":\"1234567890\"}");
//        org.junit.ComparisonFailure:
//        Expected :"{"message":"1234567890"}"
//        Actual   :""1234567890""
    }

}
@cowtowncoder
Copy link
Member

Thank you for reporting this. I hope to look into the issue in future.

Any additional info (f.ex. if possible to further isolate the cause, to see if it's filtering part, or just delegate and trunctation) would be useful.

@vy
Copy link
Contributor Author

vy commented Mar 16, 2020

Thanks for the prompt reply @cowtowncoder. In its current form, Delegate(TokenFilter(Generator)) produces the issue. Surprisingly TokenFilter(Delegate(Generator)) works okay! Further, while slightly related, TokenFilter(Generator) and Delegate(Generator) works as expected too.

If you would hint me some in the right direction, I might try to fix it myself and submit a PR.

@cowtowncoder
Copy link
Member

I was about to suggest that there are methods (like variant of writeFieldName() with SerializableString) that might need overriding. But not sure what particular one(s).
I wonder if new writeStartObject() / writeStartArray() overloads could be problematic.

@cowtowncoder cowtowncoder added 2.11 and removed 2.10 labels Apr 2, 2020
@cowtowncoder
Copy link
Member

Ok, so, the problem seems to be

void writeString(Reader reader, int len)

method, and you can work around the issue by avoiding its use. I'll see if I can fix this, but I suspect that there may be issues in trying to use Reader in filtered set up in general (since there is no way to "rewind" content) so its probably good to try to avoid its use.
Still, I may be able to solve the immediate issue here.

@cowtowncoder cowtowncoder changed the title TokenFilter with includeNull=false causes field loss in custom JsonGeneratorDelegate FilteringGeneratorDelegate does not handle writeString(Reader, int) Apr 16, 2020
@cowtowncoder
Copy link
Member

Will add a partial fix for 2.10(.4): full fix actually needs an API change in TokenFilter so only goes in 2.11.0.

cowtowncoder added a commit that referenced this issue Apr 16, 2020
cowtowncoder added a commit that referenced this issue Apr 16, 2020
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