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
#21 java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because "this.map" is null #80
Conversation
Unfortunately, the last issue is more complicated as I'm not familiar with your code structure yet. I wasn't able to identify the wrong place so far.
|
Hi @arnosthavelka and thanks for you PR! Would you mind signing the Contributor's License Agreement? https://itextpdf.com/en/how-buy/legal/itext-contributor-license-agreement |
On the PR itself: Could you add a single-threaded test demonstrating the issue?
The problem you are facing could be a side effect of a testing framework that uses multithreaded environment, in that case we will have to consider this case more carefully. The SO question you refer to is about compilation errors which we don't have. The quote from Oracle spec is also about a potential compilation error if you don't assign a final field before constructor ends, so could you elaborate on the connection of the links you mention to the issue you are experiencing? |
sure, I'll do it soon |
To prove / support my issue I changed my test from It's true, it can be still caused by my code -> even so it seems unlikely to me ;-). I'll try to provide simple test as requested. However, I cannot guarantee when.
I don't think so. But let's see with my promised test example.
Well, I have 2 objections here:
I'm not sure I understand your point. However, see the change on line 499 in my PR. Such change was forced by the compiler -> to prevent having a |
Here is the requested test:
Notes:
|
well, I've played with the test more with these discoveries:
I believe the PR is correct -> as the |
Thanks for sharing the code snippet @arnosthavelka! The root cause though is not in the fact that the What could definitely be improved of course is the exception you are getting - it's not super user friendly to just get an NPE. But you are dealing with the same document on multiple levels (higher layout level and lower kernel level) so those things on the edge might shoot out sometimes in case there is a problem in the original code. That being said, the problem is just because you are iterating over all pages after they have been created, and for documents with >=3 pages iText has already flushed first couple of pages by the time you reached your processing in The fix of the code is pretty simple - |
Thanks for letting me know the real issue.
I know. I realized that while preparing the example code. for flushing) Isn't it iText core feature I shouldn't care about? It can be an issue when generating a huge PDF with watermark, cannot it? for this PR ) Will you accept it? Otherwise I can close it. As I already wrote I believe it's an improvement. It prevents NPE as in my case. It doesn't matter what's the cause of NPE, but you logic rely on not |
It depends on your goal I think. In some cases when you operate on lower levels you should; in some cases (like yours probably) I agree that it creates undesired behavior at times. Exception should be clear, no doubt about that. In terms of the behavior itself, 95% of the users don't operate on multiple levels, and want their layout code to be concise, quick and performant and this is what happens now. Additional post-processing on lower levels like in your case needs a bit of additional care at the moment.
I don't think so. The workaround I proposed above is the most simple one but there are at least 2 other ways (overriding document renderer, adding page event listener) to achieve similar goal on the fly, without having to keep everything in memory - those ways just require a bit more code and have other tradeoffs, e.g. for tagged PDF.
If the field wasn't
The logic implies that the field becomes So what could be improved I guess is exception itself - we could add some validation on whether the object is flushed or not (object is flushed <=> map is All in all, we are happy to continue to collaborate on this PR but I think in its current shape, having the case you attached in mind, this change is not something that we would be able to merge in the codebase for the reasons I mentioned above. |
I see your point, but I don't fully agree . The flushing is done by iText (out of my hands). Therefore, it's iText's responsibility to behave correctly -> at least throw an exception when I try to get already flushed page. This way it should be clearer and avoid the confusion. However, this PR is not solving the originally targeted issue. It's not a complex fix. So, let's close it. |
Hello @Snipx, I have one more question or maybe bug. It's related to disabling of the immediate flush feature recommended by you to make the PDF generation stable. See your hint However, this flag changes the transparency behavior of the watermark. With the disabled immediate flush the watermark transparency (set by Is it a bug or there's some other configuration to make it working? |
Hey @arnosthavelka, I've taken a look at your question and generally speaking the reason of the issue is again in mixing high-level object layout and low-level content stream manipulation. You are adding instructions to the content stream and expect that the content is placed onto the content stream with One way to fix it would be to flush all the document content before adding that content stream external graphic state and flush the layout object created with
But a better and more idiomatic way to show watermark text in transparent color is just using a dedicated setter:
Now you don't need to deal with external graphics state:
Hope it helps. P.S. I suggest using StackOverflow for similar questions as it might be useful for SO community :) |
Some time ago, I have found this error on Java 15 (Java 14 seemed OK) when I upgraded to this version. Unfortunately, it's not enough, because the incorrect initialization just moved to other part. See my arnosthavelka/itext-poc#21 with more details.
The Java specification declares:
A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs.
. Clearly the new JDK tries to optimize initialization and doesn't wait before passing the instance before it's really initialized. Therefore, we have unstable code. Sometimes it's OK and sometimes it just fails.See: https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.3.1.2 or https://stackoverflow.com/questions/11345061/why-must-a-final-variable-be-initialized-before-constructor-completes
The full stacktrace looks like: