psiegman / epublib

a java library for reading and writing epub files
http://www.siegmann.nl/epublib
1.04k stars 314 forks source link

Writing epub file fails due to pull parser initialization #58

Open ediweissmann opened 10 years ago

ediweissmann commented 10 years ago

Stacktrace:

 ERROR nl.siegmann.epublib.epub.EpubWriter - Error writing table of contents: java.lang.NullPointerException: null
 ERROR nl.siegmann.epublib.epub.EpubProcessorSupport - When creating XmlSerializer: org.xmlpull.v1.XmlPullParserException: No valid serializer classes found in resource /META-INF/services/org.xmlpull.v1.XmlPullParserFactory that contained 'org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer'
 org.xmlpull.v1.XmlPullParserException: No valid serializer classes found in resource /META-INF/services/org.xmlpull.v1.XmlPullParserFactory that contained 'org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer'
 at org.xmlpull.v1.XmlPullParserFactory.newSerializer(XmlPullParserFactory.java:223)
 at nl.siegmann.epublib.epub.EpubProcessorSupport.createXmlSerializer(EpubProcessorSupport.java:81)
 at nl.siegmann.epublib.epub.EpubProcessorSupport.createXmlSerializer(EpubProcessorSupport.java:73)
 at nl.siegmann.epublib.epub.EpubWriter.writePackageDocument(EpubWriter.java:111)
at nl.siegmann.epublib.epub.EpubWriter.write(EpubWriter.java:53)
NaanProphet commented 10 years ago

Update—

Thanks to a quirk between IDEs, the above workaround did the trick in Eclipse but not in IntelliJ IDEA!

Found a solution. Adding the following dependency to my pom.xml solved the issue.

<dependency>
    <groupId>xpp3</groupId>
    <artifactId>xpp3_min</artifactId>
    <version>1.1.4c</version>
</dependency>

Special thanks to: https://community.jboss.org/thread/172860?tstart=0

Root Cause: Conflicting Service Loaders Dependencies

The real culprit, in my custom project, was an additional Maven dependency xpp3_min that overwrote the bundled service loader provider-configuration file for XmlPullParserFactory to point to org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer rather than org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer. Since neither MXParser nor MXSerializer were on the classpath, the EpubWriter.write() method blew up.

The Solution

The true solution is to copy epublib's bundled dependency net.sf.kxml:kxml2's org.xmlpull.v1.XmlPullParserFactory file from the META-INF/services/ folder into a new src/main/resources/META-INF/services/ folder in one's project. To create the file manually, the contents are simply:

org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer

This will allow the application to look for the XM classes when XmlPullParserFactory.newInstance() is called during the EpubWriter.write() method.

Potential Problem?

Note: the epublib POM currently imports xmlpull:xmlpull:1.1.3.4d_b4_min as well, which points to the MXParser and MXSerializer service loaders ... however, the MXSerializer class is not on the epublib classpath! This might help explain the problem on other environments, even when additional dependencies are not imported. Will submit a pull request with a suggested fix.

Hope this helps!

mcolburn commented 8 years ago

It is now 2016 and this problem still exists when a custom jar is created that includes epublib. I have tried both of the above solutions, and neither one works. Same errors as originally reported above.

mcolburn commented 8 years ago

I was able to work around the problem by incorporating the source code directly into my project, and by following the instructions found here:

https://github.com/psiegman/epublib/issues/14

Specifically the part that says:

Replaced the kxml2 dependency in epublib-core with xpp3

org.apache.servicemix.bundles org.apache.servicemix.bundles.xpp3 1.1.4c_4

I then replaced line 80 of EpubProcessorSupport.java from: XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); to: XmlPullParserFactory factory = new org.xmlpull.mxp1.MXParserFactory();

I also commented out line 83: //result.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);

This solved my problem, but it is an undesirable solution. It would be better if we could use Maven to include epublib as a jar and include it in our customer shaded jar and have it run without errors. Here is the error I get when I include it as a dependency in my own jar and try using it to make an epub:

ERROR nl.siegmann.epublib.epub.EpubProcessorSupport - When creating XmlSerializer: org.xmlpull.v1.XmlPullParserException: No valid serializer classes found in resource /META-INF/services/org.xmlpull.v1.XmlPullParserFactory that contained 'org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializerorg.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializerorg.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializerorg.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer'

I really love epublib. I am sad that that it is necessary to go to such lengths though to include it in our own application jar.