PowerMock java.lang.ClassCastException: sun.net.www.protocol.https.HttpsURLConnectionImpl cannot be cast to javax.net.ssl.HttpsURLConnection

人盡茶涼 提交于 2019-12-13 13:21:29

问题


I created a mock HttpsURLConnection based on an StackExchange answer:

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

...

@RunWith(PowerMockRunner.class)
public class DialogTest {
    public void mockHttpsUrlConnectionExample() throws Exception
    {
        URL mockUrl = PowerMockito.mock(URL.class);
        PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockUrl);
        HttpsURLConnection mockUrlConnection = PowerMockito.mock(HttpsURLConnection.class);
        PowerMockito.when(mockUrl.openConnection()).thenReturn(mockUrlConnection);
        PowerMockito.when(mockUrlConnection.getResponseCode()).thenReturn(200);

        // Create and call my objects ...

    }
}

However, when I use it, I'm seeing a cast exception:

java.lang.ClassCastException: sun.net.www.protocol.https.HttpsURLConnectionImpl cannot be cast to javax.net.ssl.HttpsURLConnection

The problem lies in this code:

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

...

private Boolean sendRequest(String endpoint, JSONObject requestData, Boolean throwOnAuthException) throws JSONException, IOException {
    this.responseData = null;

    try {
        String serviceURI = getServiceURI();
        String dialogUri = String.format("%s%s", serviceURI, endpoint);
        URL url = new URL(dialogUri);

        // Exception source is this cast
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

However, when I look at the source code, I see that sun.net.www.protocol.https.HttpsURLConnectionImpl implements javax.net.ssl.HttpsURLConnection

Any suggestions on how to remedy this problem?


回答1:


The issue a conflict between the regular class loader and PowerMock's

The drawback to PowerMock is the use of a custom class loader. This class loader can modify type signatures in a way that is incompatible with the default class loader.

In certain circumstances, instantiation by reflection will cause the default class loader to be used to load a type. That class loader will not know that a type has already be loaded by PowerMock, because of the use of different signatures. The result can be casting errors for objects that should implement the cast type.

To avoid this problem, first stop PowerMock from loading javax.net.ssl.HttpsURLConnection

To prevent the cast exception, use ensure javax.net.ssl.HttpsURLConnection is only loaded by one class loader. Since I cannot stop the regular class loader from being used, the best approach is to stop the PowerMock loader from acting using the @PowerMockIgnore annotation. E.g.

@PowerMockIgnore({"javax.net.ssl.*"})
@PrepareForTest(android.util.Log.class)
public class DialogTest {
...

The side effect is that PowerMock is no longer able to provide it's version of HttpsURLConnection

Next, expose HttpsURLConnection construction, and substitute a mock object

Introduce a factory for HttpsURLConnection. E.g.

public class HttpsUrlConnectionProvider {
    public HttpsURLConnection getHttpsURLConnection(String dialogUri) throws IOException {
        URL url = new URL(dialogUri);
        return (HttpsURLConnection) url.openConnection();
    }
}

Create a mock of the HttpsURLConnection object used for HTTP request E.g.

final HttpsURLConnection mockUrlConnection = PowerMockito.mock(HttpsURLConnection.class);
PowerMockito.when(mockUrlConnection, "getResponseCode").thenReturn(200);
PowerMockito.when(mockUrlConnection, "getOutputStream").thenReturn(outputStream);

// Replace the HttpsURLConnection factory with one that returns our mock HttpsURLConnection
HttpsUrlConnectionProvider mockConnFactory = new HttpsUrlConnectionProvider() {
    public HttpsURLConnection getHttpsURLConnection(String dialogUri) throws
            IOException {
       return mockUrlConnection;
    }
};
dialog.setHttpsUrlConnectionProvider(mockConnFactory);


来源:https://stackoverflow.com/questions/31157558/powermock-java-lang-classcastexception-sun-net-www-protocol-https-httpsurlconne

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!