-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
XMLExporter has several bugs/inconsistencies with BinaryExporter #2310
Comments
I figured out the problem with BitSets. It looks like DOMOutputCapsule was writing the indices of each set bit in the BitSet similar to how BitSet.toString() works, but DOMInputCapsule was reading a "1" or "0" for each bit in the set. I think having a bunch of 1s and 0s in the file seems more readable, so I went with that method and changed DOMOutputCapsule to match the behavior. Since this functionality was completely broken previously, backwards compatibility with old XML files shouldn't be an issue. I can also change it to use the indexing method if you guys think that would be better. |
Also figured out why readString() was returning defVal for empty strings. Element.getAttribute() returns an empty string when the attribute doesn't exist. It looks like DOMInputCapsule was interpreting an empty string as always meaning the attribute wasn't found, so intentionally empty strings were treated the same way as null. It now explicitly checks whether or not the attribute exists. |
Thanks for investigating these issues. Please keep up the good work! |
Is there any reason I shouldn't deprecate DOMSerializer in favor of using Transformer? DOMSerializer is only used by XMLExporter and it doesn't appear to be doing anything that can't be done with the more robust standard library classes. The apostrophe and whitespace normalization issues can sort of be solved by adding extra cases to encodeString() and the corresponding decodeString(), but that's creating another issue I haven't looked into, and anyway those methods are really just a workaround for DOMSerializer being fragile. I think the cleanest solution is to just let java's battle-tested library to the heavy lifting. |
I don't have specific insights here but I agree in general. JME suffers from a lot of "not invented here" syndrome, especially some of the older stuff. |
For the time being, I'm going to assume its OK so long as XML files written with the old version still load properly. Easy enough to revert if needed. More progress! Edit: also now fixed Savables 9341624 |
One discrepancy I noticed is that when writing buffers, BinaryExporter clobbers the buffer's position with rewind(). XMLExporter didn't used to, but I've changed it to match the BinaryExporter behavior. Really this seems like a bad behavior with BinaryExporter, but that's outside the scope of this issue, and I'd be scared to change something like that since it's used in so many different places. Is this worth making a separate issue about, or just leave it be? |
I think the |
Ok #2312 |
2d21700 |
* #2176 Make LWJGLBufferAllocator use nmemCalloc() instead of nmemAlloc() #2176 LWJGLBufferAllocator.allocate() now always returns zero-initialized buffers. * Added unit tests for JmeExporter/JmeImporter implementations Tests all write* and read* methods of OutputCapsule and InputCapsule respectively. * Fixed XMLExporter/XMLImporter BitSets Previously DOMOutputCapsule was writing indices of set bits and DOMInputCapsule was reading values of each bit. Changed DOMOutputCapsule to match the expected behavior of DOMInputCapsule. * Fixed DOMInputCapsule.readString() returning defVal for empty strings org.w3c.dom.Element.getAttribute() returns an empty string for attributes that are not found. It looks like DOMInputCapsule.readString() was interpreting an empty string as the attribute not existing, and returning defVal even when the attribute did exist and was an empty string. Now it checks explicitly whether the attribute exists. * Deprecated DOMSerializer in favor of javax.xml.transform.Transformer DOMSerializer contains several edge-case issues that were only partially worked around with the encodeString() and decodeString() helper methods. Java has a robust built-in solution to serializing Document objects, and using that instead fixes several bugs. * Fixed NullPointerException when XMLExporter writes a String[] with null Also refactored all primitive array write and read methods to be more readable and reduce duplicate code. * Made DOM capsules reuse write/read primitive array methods for buffers Further reduces duplicate code * Fixed DOMOutputCapsule.write(Savable[][]) NullPointerException Refactored write and read methods for Savables and 1 and 2 dimensional Savable arrays. Fixed NullPointerException when writing a 2d Savable array containing a null element in the outer array. * Added Savable reference consistency test to InputOutputCapsuleTest * Fixed DOMInputCapsule throwing NullPointerException when reading list DOMInputCapsule used to throw a NullPointerException when reading an Arraylist containing a null element. Also refactored list write and read methods to clean up a bit and accidentally also fixed an unrelated bug where reading ArrayList<ByteBuffer> would return a list containing all null elements. * Made XMLExporter save and load buffer positions properly. * Cleanup and formatting for XMLExporter related classes * Undid XMLExporter saving buffer positions. Not saving positions is intentional #2312 (comment) * Fixed infinite recursion with XMLExporter Writing a Savable containing a reference loop caused infinite recursion due to bookkeeping being performed after the recursive call instead of before. Also added a unit test for this to InputOutputCapsuleTest.
I've been struggling a bit with the XMLExporter recently in my game and this prompted me to write some unit tests for the JmeExporter/JmeImporter implementations. You can see the tests on my fork here:
https://github.com/JosiahGoeman/jmonkeyengine/blob/master/jme3-plugins/src/test/java/com/jme3/export/InputOutputCapsuleTest.java.
All write* and read* methods in OutputCapsule and InputCapsule respectively are tested here. I put in all the edge cases I could think of. BinaryExporter/BinaryImporter pass all tests no problemo, but XMLExporter/XMLImporter do not.
Here's the problems I've discovered so far:
Write an empty string -> Reads defVal as if attribute was not presentWrite a string containing an apostrophe/single quote -> throws IOException when readingWrite a string containing tab, newline, or carriage return -> Reads string with these characters replaced with spacesWrite any BitSet object -> Reads BitSet containing a single zeroWrite String[] containing a null string -> Reads array with null string having been replaced with an empty stringWrite a 2d array of any type except int[][] containing a null element -> Throws NullPointerException when writingWrite an ArrayList containing a null element -> Throws IOException when readingWrite an ArrayList<ByteBuffer> -> Reads ArrayList with same number of entries, but all are nullXMLExporterMREs.java
I intend to continue investigating and hopefully resolve these problems.
The text was updated successfully, but these errors were encountered: