Wiremock: JAVA 9 compatiblity

Created on 27 Sep 2017  路  12Comments  路  Source: tomakehurst/wiremock

It would be nice if wiremock would be java 9 compatible.
I ran jdeps on our project https://github.com/JabRef/jabref/issues/2594#issuecomment-331638433 and got and it complained/showed the following:
From what I found, this api is now encapsulated in java 9 (https://docs.oracle.com/javase/9/docs/api/java.xml-summary.html)

wiremock-2.8.0.jar -> java.xml
   com.github.tomakehurst.wiremock.matching.EqualToXmlPattern$SkipResolvingEntitiesDocumentBuilderFactory -> com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl JDK internal API (java.xml)

Feature request

Most helpful comment

For those using the standalone JAR with Java 9 you need to add --add-modules java.xml.bind to make it run. ie.

java --add-modules java.xml.bind -jar wiremock-standalone-2.11.0.jar

Otherwise you will get the following

2017-11-28 05:48:14.869 Outgoing bytes: <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 500 Server Error</title>
</head>
<body><h2>HTTP ERROR 500</h2>
<p>Problem accessing /sivservice/api/users. Reason:
<pre>    Server Error</pre></p><h3>Caused by:</h3><pre>java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
        at com.github.tomakehurst.wiremock.common.Encoding.encodeBase64(Encoding.java:29)
        at com.github.tomakehurst.wiremock.servlet.WireMockHttpServletRequestAdapter.getBodyAsBase64(WireMockHttpServletRequestAdapter.java:134)
        at com.github.tomakehurst.wiremock.verification.LoggedRequest.createFrom(LoggedRequest.java:58)
        at com.github.tomakehurst.wiremock.stubbing.InMemoryStubMappings.serveFor(InMemoryStubMappings.java:74)
        at com.github.tomakehurst.wiremock.core.WireMockApp.serveStubFor(WireMockApp.java:159)
        at com.github.tomakehurst.wiremock.http.StubRequestHandler.handleRequest(StubRequestHandler.java:50)
        at com.github.tomakehurst.wiremock.http.AbstractRequestHandler.handle(AbstractRequestHandler.java:44)
        at com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet.service(WireMockHandlerDispatchingServlet.java:102)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at wiremock.org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
        at wiremock.org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)
        at wiremock.org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:365)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
        at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
        at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
        at wiremock.org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at wiremock.org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
        at wiremock.org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
        at wiremock.org.eclipse.jetty.server.Server.handle(Server.java:499)
        at wiremock.org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
        at wiremock.org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:258)
        at wiremock.org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
        at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
        at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
        at java.base/java.lang.Thread.run(Unknown Source)
</pre>
<hr><i><small>Powered by Jetty://</small></i><hr/>

</body>
</html>

All 12 comments

I haven't had a lot of time to figure Java 9 out yet. Does the jdeps error indicate it can't be run at all? Or not as part of a modular app?

That class already throws a deprecation error in the build, so I've never liked it. Unfortunately it was the only way we could find to suppress spurious errors being logged to the console by the parser.

It can still be run with java 9, it is just a reminder that it depends on internal apis on which most of them have been already encapsulated:
And from what I saw: the old code has been moved to a new package: http://openjdk.java.net/jeps/255

https://blogs.oracle.com/java/get-ready-jdk9

OK, thanks for pointing this out. I'll add it to the burgeoning list of feature requests...

For those using the standalone JAR with Java 9 you need to add --add-modules java.xml.bind to make it run. ie.

java --add-modules java.xml.bind -jar wiremock-standalone-2.11.0.jar

Otherwise you will get the following

2017-11-28 05:48:14.869 Outgoing bytes: <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 500 Server Error</title>
</head>
<body><h2>HTTP ERROR 500</h2>
<p>Problem accessing /sivservice/api/users. Reason:
<pre>    Server Error</pre></p><h3>Caused by:</h3><pre>java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
        at com.github.tomakehurst.wiremock.common.Encoding.encodeBase64(Encoding.java:29)
        at com.github.tomakehurst.wiremock.servlet.WireMockHttpServletRequestAdapter.getBodyAsBase64(WireMockHttpServletRequestAdapter.java:134)
        at com.github.tomakehurst.wiremock.verification.LoggedRequest.createFrom(LoggedRequest.java:58)
        at com.github.tomakehurst.wiremock.stubbing.InMemoryStubMappings.serveFor(InMemoryStubMappings.java:74)
        at com.github.tomakehurst.wiremock.core.WireMockApp.serveStubFor(WireMockApp.java:159)
        at com.github.tomakehurst.wiremock.http.StubRequestHandler.handleRequest(StubRequestHandler.java:50)
        at com.github.tomakehurst.wiremock.http.AbstractRequestHandler.handle(AbstractRequestHandler.java:44)
        at com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet.service(WireMockHandlerDispatchingServlet.java:102)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at wiremock.org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
        at wiremock.org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)
        at wiremock.org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:365)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
        at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
        at wiremock.org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
        at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
        at wiremock.org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at wiremock.org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
        at wiremock.org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
        at wiremock.org.eclipse.jetty.server.Server.handle(Server.java:499)
        at wiremock.org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
        at wiremock.org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:258)
        at wiremock.org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
        at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
        at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
        at java.base/java.lang.Thread.run(Unknown Source)
</pre>
<hr><i><small>Powered by Jetty://</small></i><hr/>

</body>
</html>

java.xml.bind.DatatypeConverter class shouldn't be used anymore, as it has been removed in Java 11, see JEP 320. Instead, the java.util.Base64 that was introduced in Java SE 8 should be used.

I'm getting below error when I'm running Wiremock with java module.
Java version: 11
Wiremock version: 2.20.0

Can't extract module name from wiremock-standalone-2.20.0.jar: Provider class com.fasterxml.jackson.core.JsonFactory not in module

OpenJDK 11
WireMock 2.21.0

module mymodule {
    // (...)

    requires wiremock;

    // (...)
}
Caused by: java.lang.IllegalAccessError: superclass access check failed: class com.github.tomakehurst.wiremock.common.Xml$SkipResolvingEntitiesDocumentBuilderFactory (in module wiremock) cannot access class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl (in module java.xml) because module java.xml does not export com.sun.org.apache.xerces.internal.jaxp to module wiremock
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:761)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:682)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:607)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at [email protected]/com.github.tomakehurst.wiremock.core.WireMockApp.<clinit>(WireMockApp.java:74)
    at [email protected]/com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:71)
    at [email protected]/com.github.tomakehurst.wiremock.WireMockServer.<init>(WireMockServer.java:118)

Adding requires java.xml; will not help - com.sun.org.apache.xerces.internal.jaxp is not exported from within java.xml module.

This is where problematic class DocumentBuilderFactoryImpl is used:
src/main/java/com/github/tomakehurst/wiremock/common/Xml.java

public static class SkipResolvingEntitiesDocumentBuilderFactory extends DocumentBuilderFactoryImpl {
    @Override
    public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilder documentBuilder = super.newDocumentBuilder();
        documentBuilder.setEntityResolver(new SkipResolvingEntitiesDocumentBuilderFactory.ResolveToEmptyString());
        return documentBuilder;
    }

    private static class ResolveToEmptyString implements EntityResolver {
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            return new InputSource(new StringReader(""));
        }
    }
}

There is a class DocumentBuilderFactory which already has static newInstance method:

public static DocumentBuilderFactory newInstance() {
    return FactoryFinder.find(
            /* The default property name according to the JAXP spec */
            DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory"
            /* The fallback implementation class name */
            "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
}

We could make SkipResolvingEntitiesDocumentBuilderFactory extend abstract DocumentBuilderFactory (which resides within exported package java.xml.parsers) instead of current one. Then decorate instance provided by DocumentBuilderFactory#newInstance and delegate all abstract methods calls. All tests passes.

I could prepare pull request if you would like to take a look.

I've been meaning to refactor this code in pretty much exactly the way you've suggested, so I'd be very happy to merge a PR.

Great. PR here: #1098

Merged, thanks @kr5ture

Was this page helpful?
0 / 5 - 0 ratings

Related issues

davidnewcomb picture davidnewcomb  路  5Comments

liangGTY picture liangGTY  路  4Comments

jaina00 picture jaina00  路  4Comments

samdnz picture samdnz  路  3Comments

flyinfish picture flyinfish  路  3Comments