Can AspectJ is intertwined through sun.net. * Packages?

I am using AspectJ to intercept java.net.Socket calls.

I created a 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, 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 happened when the call stack looks 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 this is due to the fact that sun.net.* Packages sun.net.* not load in time due to some security manager restrictions.

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

Update 1

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

Is it possible to sun.* Weave with AspectJ?

+3
java aop aspectj aspect
Mar 18 '16 at 17:34
source share
2 answers

I have not seen setting successul to load JRE classes (bootstrap) in time. If you need this for debugging, I would go with the time of weaving the JRE classes.

This short snippet will erase the JRE jars for you and put the woven classes in one output jar. It needs org.aspectj/aspectjtools as a dependency. It also skips banks in the ext JRE subfolder, as these banks will contain multiple repeating classes and creating a jar file containing duplicate files will result in an error. I also skip jfxswt.jar from newer versions of the JRE, as it will fail due to lack of 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 woven JRE classes (added to your boot class path):

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

or in the Eclipse launch configuration:

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

I also added verbose VM argument logging for class loading so you can see which class is loaded from that place.

+4
Mar 21 '16 at 0:09
source share

Nendor was right. I cannot do LTW on JRE libraries because they are on the download path and load before AspectJ can bind them. I had to compile in time and replace the default libraries.

Here is what I did:

Files you need

 workspace |- Aspect.aj |- rt.jar |- aspectjrt-1.8.7.jar |- aspectjtools-1.8.7.jar 



Aspect.aj

 package java.net; import sun.misc.SharedSecrets; import java.io.FileDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public aspect Aspect { private static Class dualStackPlainSocketImplClass; private static Method localPort0; static { try { dualStackPlainSocketImplClass = Class.forName("java.net.DualStackPlainSocketImpl"); localPort0 = dualStackPlainSocketImplClass.getDeclaredMethod("localPort0", Integer.TYPE); localPort0.setAccessible(true); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } pointcut connect(java.net.DualStackPlainSocketImpl s): target(s) && execution(* java.net.DualStackPlainSocketImpl.socketConnect(..)); after(DualStackPlainSocketImpl s) throwing (Exception e): connect(s) { try { Field fdf = dualStackPlainSocketImplClass.getSuperclass().getSuperclass().getDeclaredField("fd"); fdf.setAccessible(true); FileDescriptor fd = (FileDescriptor) fdf.get(s); int nativeFd = SharedSecrets.getJavaIOFileDescriptorAccess().get(fd); int localPort = (int) localPort0.invoke(dualStackPlainSocketImplClass, nativeFd); System.out.format("[local port=%s][exception=%s]\n", localPort, e.getMessage()); } catch (InvocationTargetException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } catch (NoSuchFieldException e1) { e1.printStackTrace(); } catch (NullPointerException e1) { e1.printStackTrace(); } } } 

The aspect file is very simple, the difficult bit is how to get the local port through reflection.

Please note that package java.net; is important because some classes / methods are protected.




Then run from the workspace

 java -cp "aspectjrt-1.8.7.jar;aspectjtools-1.8.7.jar" org.aspectj.tools.ajc.Main -1.8 -inpath rt.jar Aspect.aj -outjar newrt.jar 

and you will get newrt.jar .




To run your program with it,

 java -cp <your_class_path> -Xbootclasspath/p:<path_to_newrt.jar> <main_class> 

-Xbootclasspath/p will add newrt.jar to the boot path and override the default JDK.

+1
Mar 23 '16 at 11:50
source share



All Articles