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

匿名 (未验证) 提交于 2019-12-03 01:21:01

问题:

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); 


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