Search code examples
javaaopaspectjaspect

Can AspectJ weave through sun.net.* packages?


I'm using AspectJ to intercept java.net.Socket calls.

I've created very simple aspect

after(): call(* java.net.Socket.connect(..)) {
    System.out.println("Connect intercepted!");
}

and aop.xml

<aspectj>

    <aspects>
        <aspect name="com.iggroup.lightstreamer.nwtp.SocketExceptionLoggingAspect"/>
    </aspects>

    <weaver options="-Xlint:ignore -Xset:weaveJavaxPackages=true -Xset:weaveJavaPackages=true">
    </weaver>

</aspectj>

When the call stack is like this, then I can see the console output:

java.lang.Exception
    at com.iggroup.lightstreamer.nwtp.SocketExceptionLoggingAspect.ajc$after$com_iggroup_lightstreamer_nwtp_SocketExceptionLoggingAspect$2$6e16217c(SocketExceptionLoggingAspect.aj:39)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:337)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:596)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475)
    at com.iggroup.lightstreamer.nwtp.users.SsoRestClientImpl.lambda$0(SsoRestClientImpl.java:68)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

But nothing is logged out when the call stack is like this:

Caused by: java.net.ConnectException: Connection refused: connect
                at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_65]
                at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_65]
                at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_65]
                at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_65]
                at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_65]
                at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668) ~[na:1.8.0_65]
                at sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173) ~[na:1.8.0_65]
                at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.openServer(HttpClient.java:432) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.openServer(HttpClient.java:527) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:781) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647) ~[na:1.8.0_65]
                at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536) ~[na:1.8.0_65]
                at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.8.0_65]
                at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) ~[na:1.8.0_65]
                at com.lightstreamer.ls_client.HttpProvider.connectAndGetAnswer(HttpProvider.java:244) ~[lightstreamer-se-client-2.5.2-1110.jar:na]

I wonder if it is because the sun.net.* packages are not load-time-weaved due to some security manager restrictions.

Does anyone know how to get it work with sun.net.* packages?

Update 1

I confirm that I can intercept the ls_client.HttpProvider.connectAndGetAnswer call, but not the one above it (sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream).

Is sun.* possible to weave with AspectJ?


Solution

  • I'm yet to see a successful setup for load-time weaving of JRE (bootstrap) classes. If you need this for debugging purposes I'd go with build time weaving of the JRE classes instead.

    This short snippet will weave the JRE jars for you and put the weaved classes in a single output jar. It needs org.aspectj/aspectjtools as a dependency. It also skips the jars in ext subfolder of the JRE as those jars will contain some duplicate classes and creating a jar file containing duplicate files will lead to an error. I'm also skipping jfxswt.jar from newer JRE versions as it will fail because of missing classes.

    String aspectFileName = "src/main/java/pckg/AspectName.aj";
    String jreLibPath = "c:/Program Files/Java/jdk1.8.0_40/jre/lib";
    String outputJar = "weavedjre.jar";
    
    List<String> jars = new ArrayList<>();
    
    File dir = new File(jreLibPath);
    File[] files = dir.listFiles();
    for (File file : files) {
        if (file.isFile() && file.getName().endsWith(".jar")
                && !file.getName().endsWith("jfxswt.jar")) {
            jars.add(file.getAbsolutePath());
        }
    }
    
    List<String> ajcArgs = new ArrayList<>(Arrays.asList("-showWeaveInfo"));
    for (String jar : jars) {
        ajcArgs.add("-inpath");
        ajcArgs.add(jar);
    }
    ajcArgs.add(aspectFileName);
    ajcArgs.add("-outjar");
    ajcArgs.add(outputJar);
    
    org.aspectj.tools.ajc.Main.main(ajcArgs.toArray(new String[] {}));
    

    Then run your program with the following VM arguments to use the weaved JRE classes (prepended to your boot classpath):

    -verbose:class -Xbootclasspath/p:path_to/weavedjre.jar
    

    or in an Eclipse launch configuration:

    -verbose:class -Xbootclasspath/p:${resource_loc:/project_name/weavedjre.jar}
    

    I added the verbose logging of class loading VM argument too, so you can see which class is loaded from where.