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

Allow registering a hook to modify/pre-process String values read #2971

Open
cowtowncoder opened this issue Dec 5, 2020 · 8 comments
Open
Labels
most-wanted Tag to indicate that there is heavy user +1'ing action

Comments

@cowtowncoder
Copy link
Member

(note: counterpart to FasterXML/jackson-core#355 -- see more discussion there)

For some use cases -- for example, variable substitution -- it would be beneficial to be able to register a handler that can replace parts of incoming String values before other databinding functionality handles it.
Since there are various ways this could occur, I'll add a databinding issue here; the original jackson-core one (see above) may be most likely way to get there, but even if so there probably needs to be a way to register such handler on per-call basis for ObjectReaders (and/or maybe ObjectMapper).

@cowtowncoder cowtowncoder added to-evaluate Issue that has been received but not yet evaluated 2.13 most-wanted Tag to indicate that there is heavy user +1'ing action and removed to-evaluate Issue that has been received but not yet evaluated labels Dec 5, 2020
@cowtowncoder cowtowncoder added 2.14 and removed 2.13 labels Jul 15, 2021
@cowtowncoder cowtowncoder added 2.15 and removed 2.14 labels Mar 15, 2023
@JooHyukKim
Copy link
Member

JooHyukKim commented Sep 20, 2023

Example usage suggestion, made it verbose(not lambda) to express that we would need interface ValuePreprocessor also.

class Bean {
    public int hello;
}

// NEW FEATURE
ValuePreprocessor processor = new ValuePreprocessor() {
    @Override
    public String preprocess(String name, String expected) {
           // do something... like trimming
          return 
    }
}

// USAGE
@Test
public test() {
    // polluted input
    String input = a2q("    {`hello`:123}           #_F#EFJ)#")

    // configure it
    ObjectMapper mapper = JsonMapper.builder()
       .registerValuePreprocessor(processor)
       .build();
    
   // use it, successfully
    assertNotNull(mapper.readValue(input, Bean.class));

   
   assertThrows(SomeDeserException.class,
       () -> mapper.reader()
                    .withoutValuePreprocessor() // <---- sometimes we may not want it?
                   .readValue(input, Bean.class));
}

@pjfanning
Copy link
Member

I'd prefer if the new class was called ValuePreprocessor and it was aimed at allowing values to be modified. So in "name": "value", it would only be allowed to change the value. I think the API in ValuePreprocessor should be public String preprocess(String name, String value). It may also be useful to have a 3rd input parameter, a type descriptor - it would be certainly be useful to know if the value is a number.

I don't know what to do about arrays like "name": [ "value1", "value2" ]. The type descriptor could be an enum of string, number, string-array, number-array. With this example we could have 2 calls to the ValuePreprocessor with the inputs:

  • name, value1, string-array
  • name, value2, string-array

If we want to make the names preprocessable, we could add a separate feature to support a NamePreprocessor.

@JooHyukKim
Copy link
Member

JooHyukKim commented Sep 20, 2023

I'd prefer if the new class was called ValuePreprocessor

Sure, I don't have preference for name yet.

preprocess(String name, String value)

Seems like name would be the JSON key to look for, but how will the parameter value be used?

@pjfanning
Copy link
Member

pjfanning commented Sep 20, 2023

Seems like name would be the JSON key to look for, but how will the parameter value be used?

If you have JSON with this:
"name1": "value1"

You get a call to the ValuePreprocessor with this:
String preprocess(name1, value1)

The ValuePreprocessor is user provided and the user may have code in their ValuePreprocessor where they want to uppercase values but only when the name value is equal to name1.

@JooHyukKim
Copy link
Member

JooHyukKim commented Sep 20, 2023

The ValuePreprocessor is user provided and the....

Thank you for the explanation 🙏🏼 I first thought the preprocessor would take in the whole input (like JSON String, .csv or .json file, etc...) and clean up input. But your usage makes sense also. I will go check again the intended usage.

P.S. Modified example usage accordingly.

@pjfanning
Copy link
Member

pjfanning commented Sep 20, 2023

The ValuePreprocessor is user provided and the....

Thank you for the explanation 🙏🏼 I first thought the preprocessor would take in the whole input (like JSON String, .csv or .json file, etc...) and clean up input. But your usage makes sense also. I will go check again the intended usage.

P.S. Modified example usage accordingly.

I could be wrong but I really don't see the point in jackson pre-processing the entire input as one string. A user can trivially do that already in their own code before asking Jackson to parse the modified input. But the ValuePreprocessor as I describe it is useful because the JSON parser has added some value by working out the structure of the input.

@JooHyukKim
Copy link
Member

I could be wrong but I really don't see the point in jackson pre-processing the entire input as one string. A user can trivially do that already in their own code before asking Jackson to parse the modified input.

I concur 👍🏼

@cowtowncoder cowtowncoder removed the 2.15 label Sep 22, 2023
@cowtowncoder
Copy link
Member Author

Correct: this would apply to String valued (Object) properties, not to whole input document.

But I suspect that

FasterXML/jackson-core#355

is more generally usable approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
most-wanted Tag to indicate that there is heavy user +1'ing action
Projects
None yet
Development

No branches or pull requests

3 participants