-
Notifications
You must be signed in to change notification settings - Fork 66
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
Show a chunk of json when mapping the object fails #84
Show a chunk of json when mapping the object fails #84
Conversation
Can we try to not use toString which is slow but direct in mem value? |
When you say direct in mem value, do you mean there is already the related chunk of json already available in memory somewhere so it can be displayed? |
@dblevins guess we can passthrough the input (stream or reader or string) and if in memory we could just use it but I was more thinking about just giving some context iterating over the object and not serializing it as JSON but more a simple toString for a subpart, something in the spirit of It has the avantage to 1. not go through a real JSON serialization, 2. not serialize the full object when you only need one field (take the example of a json object of 1m with an url, here the url is sufficient to fill the 50 chars) so it will give some context to the error but also enables to keep performances fine when error are repeated (including attack cases ;)). Hope it makes sense. |
I like it! I'll properly open a JIRA for this and rework the PR. |
4adf63a
to
23964ae
Compare
All right, I've gone ahead and made this change and squash committed over the previous attempt. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I like it, just a few details to fix for me then we are good:
- Instead of object/array cast, jsonp provide jsonvalue.asJsonXxc methods
- Some formatting issues?
- Please ensure snippet is always closing the generator otherwise it can leak the stream (not a big deal) and memory buffer (big deal ;))
Btw I really like the mix of ideas you did ;)
I've updated the code to remove the casting. On formatting, I'd need some pointers on what should be updated as the checkstyle passed. There is a call to FYI, none of the existing
I can send a separate PR for that if you like. |
Sure, try/finally (or autoclose), no assumption it will be called...cause it can fail in between.
Json /JsonProviderImpl ).
Long story short the idea would be something along this: https://gist.github.com/rmannibucau/bc400921f17dd12eb86491462071b0e9 . |
Thanks for the clarification on the formatting -- I hadn't noticed that code was reformatted. Mixing reformatting and real changes is also on my no-no list :) I'll fix and again squash the commit so the reformatting is not in the history. I'll fix the try/finally close and then take a closer look at the diff. |
a8f367b
to
2ac98b7
Compare
Ok, all that feedback should be addressed and I must say the result of having bounced this back and forth is really looking great! Effectively, Thank you so very much for the code that handled the internal plumbing. That's the kind of code so painful to figure out when you don't know the codebase / hard to describe even when you do. I greatly appreciate the assist and made it clear in the commit message you are the real author. Such a truly fun collaboration!! |
Hi David, Looked quickly but seems several changes are lost or unintended like the double call to generator.close, the snippet creation using Json and not the configured JsonGeneratorFactory, the parser close call miss in tests or the fix in test/truncation behavior to respect max config. |
You're right -- I missed the code for JohnzonBuilder and the wildcard builder. I went ahead and added it along with a test case to verify the The supplied The I've significantly amped up the testing, reworked the code and all is looking good -- famous last words. Give it a good look and let me know if anything looks off. |
Second constructor is only used in test this is why i would drop it from main code since we will never want to allow its usage. For close we must find a way to call it once and it should be fine with autocloseable so I suspect buffer was buggy. Last thing is the bug for primitive we should fix since truncation should be respected there too, no passthrough IMHO ;). |
Can you check the code again? The tests don't use the second constructor and close is called only once. I'm not convinced trimming things like null to things like |
Ok so the second constructor is never useful since there is always a generator factory in scope so let's drop it. About null truncation the question is "is a snippet of size < 4 useful" but it can be configured and if so respected (size shouldnt be > its max including the ellipsis if we want to document properly and simply this config IMO). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
two minor comments (mainly dropping the error prone constructor and flushes which are not needed) then looks perfect for me
* | ||
* @param max the maximum length of the serialized json produced via of() | ||
*/ | ||
public Snippet(final int max) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd really drop this one since minimum would be to require to copy the config (except the buffer size maybe) from the mapper one which is likely equivalent to use the mapper one as we do in the other constructor.
Also note that the buffer size is not important since before using any output we should flush it as any "output stream" so this one should drop IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you comment this constructor must not be used in johnzon project please but is only there for convenience for intergators and that using it disable several features of the project?
johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
Outdated
Show resolved
Hide resolved
johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
Outdated
Show resolved
Hide resolved
johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
Outdated
Show resolved
Hide resolved
johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
Outdated
Show resolved
Hide resolved
I'll review the comments in detail, but I'd like to offer a compromise. I'll make the change to "null", etc being truncated that I don't agree with in exchange for you allowing the Snippet(int) constructor and Snippet.of(value, int) static method to live. I use Johnzon in almost every project and I'd really like the ability to use this code elsewhere and have those methods. |
@dblevins hmm, what I really dislike in this constructor is the fact I want to totally forbid it to be used inside the project itself for the reason mentionned earlier. I would be happy if you do a johnzon-snippet module exposing such a constructor and using |
Not my preference, but implementing in the hope of compromise
Call flush only before snippet.terminate() and snippet.get() Reduce calls to snippet.terminate() to only what is needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few picky comments but the big one is the change from outpustream to writer which moves the code to use the default charset instead of reusing the one from the generator factory, was it intended? how is it supposed to work now/what am I missing?
* | ||
* @since 1.2.17 | ||
*/ | ||
public interface Buffered { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more a question than anything else: shouldnt it be Bufferable
or something like that? (not blocking for me but asking before it gets merged)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My first instinct was Bufferable as well. What swayed me away is the "able" interfaces are all describing an action someone can take on the object and if they don't take that action, the thing described is not done. If you don't serialize a Serializable
it isn't serialized. If you don't close a Closeable
it isn't closed. Flushable
objects of course do flush eventually, but the method it has still triggers an action. So calling it Bufferable
felt a bit off as there's no action for the user to do. It's buffered whether or not the user does anything and calling bufferSize
does nothing. Buffered
is a statement of fact and bufferSize
returns that fact.
All that said, I'm not super married to it. That's just the logic that got me there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, guess the same reasoning got me asking the question, while not handled by johnzon it is not buffered.
What if we quit that area and call it StreamDescriptor
which would be more OO (i am an instance of stream descriptor so I can get meta about the stream/writer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally like Buffered
as it is telling Johnzon a fact, "I am buffered". There is a ByteArrayOutputStream inside the supplied SnippetWriter that Johnzon doesn't control. Johnzon can look at the writers and outputstreams it is given and use the interface to ask, "are you buffered?" and if they are Johnzon can optimize its own buffering to match their buffer size. So to me it makes sense as there's a conversation there:
johnzon: are you buffered?
writer: yes, I'm buffered.
johnzon: Ok, what's your buffer size?
writer: It's 50.
johnzon: great, I'll write to you 50 bytes at a time
That said, if you'd like to rename it after the merge I'm ok with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see where you coming from. I was more seeing it as:
johnzon: do you want to be buffered?
writer: yes, I need a custom buffer.
johnzon: Ok, what's your buffer requested size?
writer: It's 50.
johnzon: great, I'll write to you 50 bytes at a time
let me try to PR on top of your PR but this is not the critical point, was more curious ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. As I said to me it makes sense. We could easily get a Writer that writes to a file and has a buffer in it optimized for the page size of disk. This interface would be a great way for them to tell that fact to Johnzon so it can participate in the optimization. Ideally, whatever interface name use use it is strongly tied to buffering and not generic and therefore has many other purposes in the future. If we did that, then it would get complicated for someone to say, "Yes, I am buffered, but I am not those other things."
@@ -236,7 +238,8 @@ public Mapper build() { | |||
supportEnumContainerDeserialization, | |||
typeLoader, discriminatorMapper, discriminator, | |||
deserializationPredicate, serializationPredicate, | |||
enumConverterFactory), | |||
enumConverterFactory, | |||
new Snippet(snippetMaxLength, generatorFactory)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we must be able to run with any JSON-P impl so we likely need some indirection there (fine to not be optimum if we don't run with johnzon-core but a generic json-p impl)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might have been a comment for the constructor as it referenced JsonGeneratorFactoryImpl. I updated it back to Json.createGeneratorFactory. If that wasn't what you meant, I sent an invite to the repo so you have access to do any adjustments you'd like.
* | ||
* @param max the maximum length of the serialized json produced via of() | ||
*/ | ||
public Snippet(final int max) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you comment this constructor must not be used in johnzon project please but is only there for convenience for intergators and that using it disable several features of the project?
public String of(final JsonValue value) { | ||
try (final Buffer buffer = new Buffer()) { | ||
buffer.write(value); | ||
return buffer.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was expecting that moving get() after the auto-close try block would auto-flush it, isn't it right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to have the buffer instance constructed inside the try-with-resources as I like the assurance there can be 100% certain there can be no possible leak. If we don't like flush, we could call close which is documented to idempotent and safe to call more than once. Johnzon properly implements idempotent closes so it is safe. If a JSON-P impl doesn't properly implement close and fails, that'd be their bug IMO.
That said, I'm ok if you'd like to adjust it.
Ok, I've made most the changes. I'm happy for there to be other changes and have provided access to my fork so you have the option to do that before anything is merged. I offer that in the spirit of speed as I only have a few more days to do all the message work and haven't even started yet. Feel free to make any change you need to feel confident merging. |
@rmannibucau happy for you to push directly to this repo so I can feel happy seeing a purple "merged" symbol on this PR. |
@rmannibucau alternatively, you could merge it and then do a PR on top of master. Personally, I don't think anything in this PR is too dangerous to merge at this point. |
ok let's do it |
Who hooo!! :) That feels great! :) |
Thank you, @rmannibucau !! I really enjoyed the help and collaboration. |
This appears in a stacktrace like the following