在OpenJDK代码中调试NullPointerException(在Sun类中)

时间:2016-07-11 06:50:23

标签: java jvm openjdk

在我的一个客户日志中,我看到了Sun类的异常。客户端使用OpenJDK 1.8.0_91。

我试图在没有任何运气的情况下重现它。

从我们的日志中,似乎我在关闭JVM期间(在ShutdownHook中)收到异常。

问题是这段代码在程序的生命周期内工作,并按预期发送所有数据,但是在关机期间,我们不时会得到这个NPE。

关于如何解决的任何想法?我试图查看源代码但由于某种原因我无法找到它。

这是堆栈跟踪:

    2016-07-08 11:07:58,426 ERROR [Thread-0] [HttpClient] Failed to send 'POST' request to 'https://prod-x-gw.mycompany.co/api/v2/testDoMagic/'. Error: java.lang.NullPointerException
java.lang.NullPointerException: null
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1158) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:999) ~[na:1.8.0_91]
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258) ~[na:1.8.0_91]
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250) ~[na:1.8.0_91]
    at com.my.company.HttpClient.writeRequestBodyToOutputStream(HttpClient.java:152) ~[na:na]
    at com.my.company.HttpClient.sendRequest(HttpClient.java:52) ~[na:na]
    at com.my.company.JsonClient.sendHttpRequest(JsonClient.java:187) [na:na]
    at com.my.company.JsonClient.postRequest(JsonClient.java:92) [na:na]
    at com.my.company.JsonClient.postRequest(JsonClient.java:86) [na:na]
    at com.my.company.DoMagicServiceProxy.sendRequest(DoMagicServiceProxy.java:59) [na:na]
    at com.my.company.DoMagicServiceProxy.submitDoMagic(DoMagicServiceProxy.java:48) [na:na]
    at com.my.company.DoMagicQueueSender$2.process(DoMagicQueueSender.java:108) [na:na]
    at com.mycompany..commons.ChunksProcessor.processAsChunks(ChunksProcessor.java:35) [na:na]
    at com.my.company.DoMagicQueueSender$1.execute(DoMagicQueueSender.java:89) [na:na]
    at com.my.company.DoMagicQueueSender.shutdown(DoMagicQueueSender.java:46) [na:na]
    at com.mycompany.DoMagicManager.shutDown(DoMagicManager.java:77) [na:na]
    at com.mycompany.AM.shutdown(AM.java:145) [na:na]
    at com.mycompany.AM.access$000(AM.java:17) [na:na]
    at com.mycompany.AM$1.run(AM.java:157) [na:na]
2016-07-08 11:07:58,437 ERROR [Thread-0] [DoMagicServiceProxy] Failed while trying to submit DoMagic. Error:
java.lang.RuntimeException: Failed to send 'POST' request to 'https://prod-x-gw.mycompany.co/api/v2/testDoMagic/'. Error: java.lang.NullPointerException
    at com.my.company.HttpClient.sendRequest(HttpClient.java:70) ~[na:na]
    at com.my.company.JsonClient.sendHttpRequest(JsonClient.java:187) ~[na:na]
    at com.my.company.JsonClient.postRequest(JsonClient.java:92) ~[na:na]
    at com.my.company.JsonClient.postRequest(JsonClient.java:86) ~[na:na]
    at com.my.company.DoMagicServiceProxy.sendRequest(DoMagicServiceProxy.java:59) ~[na:na]
    at com.my.company.DoMagicServiceProxy.submitDoMagic(DoMagicServiceProxy.java:48) ~[na:na]
    at com.my.company.DoMagicQueueSender$2.process(DoMagicQueueSender.java:108) [na:na]
    at com.mycompany.commons.ChunksProcessor.processAsChunks(ChunksProcessor.java:35) [na:na]
    at com.my.company.DoMagicQueueSender$1.execute(DoMagicQueueSender.java:89) [na:na]
    at com.my.company.DoMagicQueueSender.shutdown(DoMagicQueueSender.java:46) [na:na]
    at com.mycompany.DoMagicManager.shutDown(DoMagicManager.java:77) [na:na]
    at com.mycompany.AM.shutdown(AM.java:145) [na:na]
    at com.mycompany.AM.access$000(AM.java:17) [na:na]
    at com.mycompany.AM$1.run(AM.java:157) [na:na]
Caused by: java.lang.NullPointerException: null
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1158) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:999) ~[na:1.8.0_91]
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283) ~[na:1.8.0_91]
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258) ~[na:1.8.0_91]
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250) ~[na:1.8.0_91]
    at com.my.company.HttpClient.writeRequestBodyToOutputStream(HttpClient.java:152) ~[na:na]
    at com.my.company.HttpClient.sendRequest(HttpClient.java:52) ~[na:na]
    ... 13 common frames omitted

如果这有帮助,我就是我的HttpClient实现:

public class HttpClient {
private int readTimeoutInMS;
private int connectTimeoutInMS;
private String charset;
private final int SECOND = 1000;
private ILogFactory logFactory;
private ILogger log;

public HttpClient(){
    //By default, max timeout will be 130 seconds - 10 seconds to connect, and 120 seconds to read the final byte.
    connectTimeoutInMS = 10 * SECOND;
    readTimeoutInMS = 120 * SECOND;
    charset = "utf-8";
}

public void init() {
    if (log == null) {
        log = getLogger();
    }
}

public HttpResponse sendRequest(HttpRequest request)
{
    log.info("sendRequest was called. Remote url:'" + request.getUrl() + "'.");
    HttpRequestMethods requestMethod = request.getRequestMethod();
    HttpURLConnection connection = null;
    boolean originalFollowRedirects = HttpURLConnection.getFollowRedirects();
    try{

        URL targetUrl = new URL(request.getUrl());
        connection = (HttpURLConnection) targetUrl.openConnection();

        setupConnectionObject(request, requestMethod, connection);

        if (requestMethod == HttpRequestMethods.POST){
            writeRequestBodyToOutputStream(request, connection);
        }

        HttpResponse response = new HttpResponse();
        response.setStatusCode(connection.getResponseCode());
        if (response.getStatusCode() >= 400) {
            response.setResponseStream(connection.getErrorStream());
        }
        else {
            response.setResponseStream(connection.getInputStream());
        }

        return response;

    }catch (Exception e)
    {
        String msg = String.format("Failed to send '%s' request to '%s'. Error: %s", requestMethod, request.getUrl(), e);
        log.error(msg,e);
        throw new RuntimeException(msg, e);
    }
    finally {

        HttpURLConnection.setFollowRedirects(originalFollowRedirects);
    }
}


public int getReadTimeoutInMS() {
    return readTimeoutInMS;
}

public void setReadTimeoutInMS(int readTimeoutInMS) {
    this.readTimeoutInMS = readTimeoutInMS;
}

public int getConnectTimeoutInMS() {
    return connectTimeoutInMS;
}

public void setConnectTimeoutInMS(int connectTimeoutInMS) {
    this.connectTimeoutInMS = connectTimeoutInMS;
}


public String getCharset() {
    return charset;
}

public void setCharset(String charset) {
    this.charset = charset;
}

public ILogFactory getLogFactory() {
    return logFactory;
}

public void setLogFactory(ILogFactory logFactory) {
    this.logFactory = logFactory;
}

private void setupConnectionObject(HttpRequest request, HttpRequestMethods requestMethod, HttpURLConnection connection)throws ProtocolException {
    connection.setRequestMethod(requestMethod.toString());

    if (requestMethod == HttpRequestMethods.POST){
        //Mark the HttpMethod as post.
        connection.setDoOutput(true); // Allows to send message body on the output stream.
    } else if (requestMethod == HttpRequestMethods.HEAD)
    {
        HttpURLConnection.setFollowRedirects(false);
        connection.setRequestMethod("HEAD");
    }

    int connectTimeout = request.getConnectTimeout() != null? request.getConnectTimeout() : this.connectTimeoutInMS;
    if (connectTimeout >= 0)
    {
        connection.setConnectTimeout(connectTimeout);
    }

    int readTimeout = request.getReadTimeout() != null? request.getReadTimeout() : this.readTimeoutInMS;
    if (connectTimeout >= 0)
    {
        connection.setReadTimeout(readTimeout);
    }

    //Add HttpHeader
    if (request.getHttpHeaders() != null)
    {
        for (Entry<String, String> httpHeader : request.getHttpHeaders().entrySet()) {
            connection.setRequestProperty(httpHeader.getKey(), httpHeader.getValue());
        }
    }
    if (request.getCompressRequestBody() && connection.getDoOutput()){ //only turn on for request with output
        connection.setRequestProperty("Content-Encoding","gzip");
    }
}
private void writeRequestBodyToOutputStream(HttpRequest request,
        HttpURLConnection connection) throws IOException,
        UnsupportedEncodingException {
    DataOutputStream dataOutputSteam = null; 
    try{
        dataOutputSteam = new DataOutputStream(connection.getOutputStream());
        String requestBody = request.getRequestBody() != null ? request.getRequestBody() : "";
        String bodyCharset = request.getCharset() != null ? request.getCharset() : this.charset;
        byte[] requestBodyAsBytes = requestBody.getBytes(bodyCharset);

        if (request.getCompressRequestBody()) {
            //http://stackoverflow.com/questions/7153484/gzip-post-request-with-httpclient-in-java
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
                gzos.write(requestBodyAsBytes);
            }

            byte[] gzippedBytes = baos.toByteArray();
            requestBodyAsBytes = gzippedBytes;
        }
        dataOutputSteam.write(requestBodyAsBytes);
    }
    finally{
        if (dataOutputSteam != null)
        {
            dataOutputSteam.close();
        }
    }
}

private ILogger getLogger() {
    ILogger logger;
    if (logFactory != null)
    {
        logger = logFactory.getLogger("HttpClient");
    }
    else
    {
        logger = NullLogger.INSTANCE;
    }
    return logger;
}

}

1 个答案:

答案 0 :(得分:2)

我的猜测是,在退出之前最终清理期间连接实际上仍在使用时,你断开了与该URL的连接(可能是一些终结器完成其工作的结果),事实上它只是偶尔发生您正在同时使用该HttpURLConnection而没有正确同步。

检查来源here,在此版本的HttpURLConnection.plainConnect0()中该行应为1156而不是1158

尝试在HttpURLConnection.disconnect()上设置断点(仅适用于该网址?)。