Is there a (pref portable) way to check if
The JVM has been stated with a particular -javaagent?
In particular I'm interested to know if the aspectj load time weaver has loaded or not. (I'm trying to provide a helpful error msg in the case of incorrect startup).
The following code shows
a way to determine any -javaagent:... JVM arguments,
a way to check if the AspectJ weaving agent entry point class (the one mentioned in the manifest entry Premain-Class: of aspectjweaver.jar) is loaded.
The former just proves that the argument was given on the command line, not that the agent was actually found and started.
The latter just proves that the weaver is available on the classpath, not that it was actually started as an agent. The combination of both should give you pretty much confidence that the agent is actually active.
package de.scrum_master.app;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
public class Application {
public static void main(String[] args) {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
for (String argument : arguments) {
if (argument.startsWith("-javaagent:"))
System.out.println(argument);
}
try {
Class.forName("org.aspectj.weaver.loadtime.Agent");
} catch (ClassNotFoundException e) {
System.err.println("WARNING: AspectJ weaving agent not loaded");
}
}
}
You also might find the question Starting a Java agent after program start and some of its answers helpful.
Update:
Okay, here is a combination of my own solution and yours, but one which actually works even if the weaver is unavailable, which is important because this is what you want to check in the first place:
public static boolean isAspectJAgentLoaded() {
try {
Class<?> agentClass = Class.forName("org.aspectj.weaver.loadtime.Agent");
Method method = agentClass.getMethod("getInstrumentation");
method.invoke(null);
} catch (Exception e) {
//System.out.println(e);
return false;
}
return true;
}
Update 2:
After some discussion with the OP bacar I have decided to offer a solution which does not use reflection but catches NoClassDefError instead:
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
} catch (NoClassDefFoundError | UnsupportedOperationException e) {
System.out.println(e);
return false;
}
return true;
}
Now both main error types
weaving agent is available on the classpath, but instrumentation has not been initiated because aspectjweaver.jar was not started as a Java agent,
agent aspectjweaver.jar is not on the classpath at all and class org.aspectj.weaver.loadtime.Agent is thus unavailable
are handled gracefully by returning false after warning messages (in this simple examples just the exceptions which say clearly what is wrong) have been printed on the console.
Possible console outputs for the two cases are:
java.lang.UnsupportedOperationException: Java 5 was not started with preMain -javaagent for AspectJ
java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent
I've found the following works (tested against 1.8.4), although it relies on undocumented aspectjweaver features so may not work across versions.
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
return true;
} catch (UnsupportedOperationException e) {
return false;
}
}
Explanation: when aspectj is loaded as an agent, the org.aspectj.weaver.loadtime.Agent.premain(...) static method is invoked by the JVM. This has a side effect we can test for. Calling getInstrumentation either throws UnsupportedOperationException (if it was not initialised as an agent) or returns successfully if it was.
Related
I'm trying to measure the time for certains method of some specific classes. I'm using ByteBuddy and I created the following interceptor class:
public class TimingInterceptor {
#RuntimeType
public static Object intercept(#Origin Method method,
#SuperCall Callable<?> callable) {
long start = System.currentTimeMillis();
try {
return callable.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(method + " took " + (System.currentTimeMillis() - start));
}
return null;
}
}
And this is the Java Agent Class I'm using:
public class TimerAgent {
public static void premain(String arguments,
Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameStartsWith("BP")) // This is because I used the prefix BP to name methods I need to measure
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(TimingInterceptor.class))
).installOn(instrumentation);
}
}
I ran a test application including methods named with "BP" as prefix, and the message in the class TimingInterceptor indicating the method duration is not shown.
Some ideas guys?
Example full code:
Agent: https://github.com/rauldevilla/byte-buddy-agent
Test application: https://github.com/rauldevilla/byte-buddy-lab
To debug issues, it is always a good idea to register an AgentBuilder.Listener with your agent. The instrumentation API in the JVM suppresses all exceptions that are thrown during an instrumentation and the listener allows you to catch those exceptions and to print them for example.
For such "around" instrumentation, I generally recommend using Advice as it does not make assumptions on class loader hierarchies which you need to address explicitly when using delegation.
The project I am working on is an API to support two different platforms. At runtime only one of the two platforms will actually be available on the classpath.
For the most part, I have been pretty easily able to write code like this that works fine
if (isPlatformOne()) {
PlatformOne.doSomething();
}
Even if PlatformOne does not exist at runtime, the check beforehand means the code does not run and no error will be thrown. This technique works for the VAST majority of situations however there is one case that I have run into where an error is thrown.
If PlatformOne also implements a nonexistent interface AND that is used with a parameter that ALSO does not exist, then a NoClassDefFoundError is thrown immediately when the containing class is loaded, regardless of whether the code actually executes or not.
Here's an example:
Interface:
public interface DeleteInterface {
void test(DeleteInterface delete);
}
Class:
public class DeleteClass implements DeleteInterface {
#Override
public void test(DeleteInterface delete) {
}
}
Main:
public class Test {
private final boolean test; //Cannot be constant or compiler will erase unreachable code
public Test() {
test = false;
}
public static void main(String[] args) {
if (new Test().test) {
DeleteClass c = new DeleteClass();
c.test(c);
}
System.out.println("SUCCESS!");
}
}
Deleting DeleteClass and DeleteInterface from the jar produces the following error at runtime:
A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/kmecpp/test/DeleteInterface
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.kmecpp.test.DeleteInterface
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
Why is an error thrown only for this specific case, and what's the best way to work around it without access to any of the target platforms' code?
Java validator might throw NoClassDefFoundError before even fully loading your class because of additional validations, like method return types must exist, additionally you are doing that in your Main class that is scanned by JRE on launch as you can see in stack-trace.
Move code that requires not-existing code to other class and then in place where you want to use it first check if that class exist and then invoke method from that extra class:
class MyExtraClass {
public static void doStuff() {
DeleteClass c = new DeleteClass();
c.test(c);
}
}
public boolean checkForClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
// somewhere in your code
if (checkForClass("package.DeletedClass")) {
MyExtraClass.doStuff();
}
This is just safest option for such cases, also if this is very short code you can just use some local class: (but it does not look good in most cases)
// somewhere in your code
if (checkForClass("package.DeletedClass")) {
new Runnable() {
#Override
public void run() {
DeleteClass c = new DeleteClass();
c.test(c);
}
}.run();
}
I had this issue today actually.
Make sure that you are not loading the same class twice in the systems class loader.
I.E) I had a reference being made to a.b.class in a front-end thread, and I was attempting to reference a library method with the same path and class name, and thus threw the same error for me.
I changed the names in the agent references to be different from the front-end references and the error ceased.
hope this can help
Deleting DeleteClass and DeleteInterface from the jar produces the
following error at runtime:
If the needed class does not exist at runtime, for sure, java.lang.NoClassDefFoundError will be thrown.
Even if PlatformOne does not exist at runtime, the check beforehand
means the code does not run and no error will be thrown.
Please check if your code digested the error thrown, if yes, your app won't crash and can execute as normal. E.g. below code snippet will throw the NoClassDefFoundError but won't crash because that you digest the error.
public bool isPlatformOne() {
try {
...
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
If your use case is just to check if a particular class exists, then you can use Class.forName to check the class's existence. E.g.
// className is the fully qualified class name.
public boolean hasClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
Example for using it in code.
if (hasClass("android.support.v7.app.AppCompatActivity")) {
...
}
I want to individually log every unique error I have, as searching though a dozen log files each +10k lines in length is time wasting and tedious.
I catch all exceptions I possibly can, but oftentimes other threads or libraries will shoot off their own errors without any way to process them myself.
Is there any workaround for this?
(E.G. an event for when printStackTrace() is called.)
Is there any workaround for this?
(E.G. an event for when printStackTrace() is called.)
Remap System.err to intercept throwables. If you look at the source code for Throwable.printStackTrace() you'll see that it indirectly calls System.err.println(this);
For example:
import java.io.PrintStream;
public class SpyPrintStream extends PrintStream {
public static void main(String[] args) {
System.setErr(new SpyPrintStream(System.err));
System.setOut(new SpyPrintStream(System.out));
new Exception().printStackTrace();
}
public SpyPrintStream(PrintStream src) {
super(src);
}
#Override
public void println(Object x) {
if (x instanceof Throwable) {
super.println("Our spies detected "+ x.getClass().getName());
}
super.println(x);
}
}
Keep in mind there is all kinds of issues with using this code and it is not going to work in cases where printStackTrace is called with stream that is not standard stream.
You could always do a deep dive into java.lang.instrument if you really want to trap all exceptions.
I catch all exceptions I possibly can, but oftentimes other threads or libraries will shoot off their own errors without any way to process them myself.
Most libraries either throw exceptions back to the caller or use a logging framework. Capture the exception or configure the logging framework.
I want to individually log every unique error I have, as searching though a dozen log files each +10k lines in length is time wasting and tedious.
Logging frameworks include options to deal with this. DuplicateMessageFilter is an example.
Food for thought:
public class DemoClass {
private Map<String, Exception> myExceptions = new HashMap<>();
public void demoMethod() {
try {
// throwing an exception for illustration
throw new IOException("some message");
} catch (IOException e) {
myExceptions.putIfAbsent(e.getLocalizedMessage(), e);
// actually handle the exception
...
}
}
public void finished() {
for (Exception e : myExceptions.values()) {
e.printStackTrace();
}
}
}
You could store any exception you haven't seen yet. If your specific scenario allows for a better way to ensure you only save an exception only once you should prefer that over mapping by Exception.getLocalizedMessage()
Some 3rd party library swallowed an Exception:
String getAnswer(){
try{
// do stuff, modify instance state, maybe throw some exceptions
// ...
return computeAnswer();
}catch (SomeException e){
return null;
}
}
As much as I want to change it into:
String getAnswer() throws SomeException{
// do stuff, modify instance state, maybe throw some exceptions
// ...
return computeAnswer();
}
I can't, because the library is already packaged into a jar. So, is there a way to bring the exception back?
I don't need to rethrow, a stacktrace with exception and message would work too.
I don't think reflection would help here, Unsafe perhaps?
Yes I know I can use a debugger to find out what's happening, but that wouldn't be very useful if I need the exception at runtime for logging and stuff like that
You can do it without reflection or AOP. The main idea is to throw another (unchecked) exception in the constructor of SomeException. There are some limitations (see at the end of this answer) but I hope it fits your needs.
You need to replace the SomeException with a new version (just create a SomeException.java file in the original package but in your src directory) with something like :
package com.3rdpartylibrary;
public class SomeException extends Exception {
public static class SomeExceptionWrapperException extends RuntimeException {
public SomeExceptionWrapperException(final SomeException ex) {
super(ex.getMessage(), ex);
}
}
public SomeException(final String message) {
super(message);
throw new SomeExceptionWrapperException(this); //<=== the key is here
}
}
The SomeExceptionWrapperException has to be unchecked (inherit from RuntimeException or Error). It will be our wrapper to carry the SomeException accross the ugly 3rd party catch(...)
Then you can catch the SomeExceptionWrapperException in your code (and eventually rethrow the original SomeException:
//original, unmodifiable 3rdParty code, here as a example
public String getAnswer() {
try {
//some code
throw new SomeException("a message");
} catch (final SomeException e) {
return null;
}
}
//a wrapper to getAnswer to unwrapp the `SomeException`
public String getAnswerWrapped() throws SomeException {
try {
return getAnswer();
} catch (final SomeExceptionWrapperException e) {
throw (SomeException) e.getCause();
}
}
#Test(expected = SomeException.class)
public void testThrow() throws SomeException {
final String t = getAnswerWrapped();
}
The test will be green as the original SomeException, will be thrown.
Limitations:
This solution will not work if either :
if SomeException is in java.lang as you cannot replace java.lang classes (or see Replacing java class?)
if the 3rd party method has a catch(Throwable e) (which will be horrible and should motivate you to ignore the full 3rd party library)
To solve this based on your constraints I would use aspects (something like AspectJ) and attach it to the creation of your exception, logging (or having it call some arbitrary) method then.
http://www.ibm.com/developerworks/library/j-aspectj/
If all you're looking for is to log the stacktrace + exception message, you could do that at the point you're throwing your exception.
See Get current stack trace in Java to get the stack trace. You can simply use Throwable.getMessage() to get the message and write it out.
But if you need the actual Exception within your code, you could try and add the exception into a ThreadLocal.
To do this, you would need a class like this that can store the exception:
package threadLocalExample;
public class ExceptionKeeper
{
private static ThreadLocal<Exception> threadLocalKeeper = new ThreadLocal<Exception>();
public static Exception getException()
{
return threadLocalKeeper.get();
}
public static void setException(Exception e)
{
threadLocalKeeper.set(e);
}
public static void clearException()
{
threadLocalKeeper.set(null);
}
}
... then in your code which throws the Exception, the code that the 3rd party library calls, you can do something like this to record the exception before you throw it:
package threadLocalExample;
public class ExceptionThrower
{
public ExceptionThrower()
{
super();
}
public void doSomethingInYourCode() throws SomeException
{
boolean someBadThing = true;
if (someBadThing)
{
// this is bad, need to throw an exception!
SomeException e = new SomeException("Message Text");
// but first, store it in a ThreadLocal because that 3rd party
// library I use eats it
ExceptionKeeper.setException(e);
// Throw the exception anyway - hopefully the library will be fixed
throw e;
}
}
}
... then in your overall code, the one that calls the third party library, it can setup and use the ThreadLocal class like this:
package threadLocalExample;
import thirdpartylibrary.ExceptionEater;
public class MainPartOfTheProgram
{
public static void main(String[] args)
{
// call the 3rd party library function that eats exceptions
// but first, prepare the exception keeper - clear out any data it may have
// (may not need to, but good measure)
ExceptionKeeper.clearException();
try
{
// now call the exception eater. It will eat the exception, but the ExceptionKeeper
// will have it
ExceptionEater exEater = new ExceptionEater();
exEater.callSomeThirdPartyLibraryFunction();
// check the ExceptionKeeper for the exception
Exception ex = ExceptionKeeper.getException();
if (ex != null)
{
System.out.println("Aha! The library ate my exception, but I found it");
}
}
finally
{
// Wipe out any data in the ExceptionKeeper. ThreadLocals are real good
// ways of creating memory leaks, and you would want to start from scratch
// next time anyway.
ExceptionKeeper.clearException();
}
}
}
Beware of ThreadLocals. They have their use, but they are a great way of creating memory leaks. So if your application has a lot of threads that would execute this code, be sure to look at the memory footprint and make sure the ThreadLocals aren't taking up too much memory. Being sure to clear out the ThreadLocal's data when you know you no longer need it should prevent that.
JVMTI agent can help. See the related question.
I've made an agent that calls Throwable.printStackTrace() for every thrown exception, but you may easily change the callback to invoke any other Java method.
A rather dirty trick that could do the job with less effort than AOP or de-/recompile the JAR:
If you can copy the source code, you can create a patched version of the class in question with your version of the getAnswer method. Then put it on your classpath before the third party library that contains the unwanted version of getAnswer.
Problems could arise if SomeException is not a RuntimeException and other third party code calls getAnswer. In this situation I am not sure how the resulting behavior will be. But you could circumvent this by wrapping SomeException in a custom RuntimeException.
Could you not just use a reference variable to call that method, if the result is a null, then you can just display a message/call an exception, whatever you want?
if you're using maven, you would exclude packages of the library.
Dependency Exclusions.
I hope to be helpful
If you have the source to the throwing class, you can add it "in the original package but in your src directory" using the technique as #BenoƮt has pointed out. Then just change
return null;
to
return e;
or
e.printStackTrace();
etc.
This would be quicker then making a new Exception.
Rewritten from scratch # Friday, 25 May, about 16:00 GMT
(Code is cleaner now, bug can be reproduced and the question is more clear)
Original problem: I'm writing a server app that's required to accept files from clients over the net and process them with certain classes, which are loaded from locally stored .jar-files via URLClassLoader. Almost everything works correctly, but those jar-files are hot-swapped (without restarting the server app) from time to time to apply hotfixes, and if we're unlucky enough to update .jar-file at the same time class from it is being loaded, ClassFormatError is thrown, with remarks about "truncated class" or "excess bytes at the end". That's to be expected, but the whole application becomes unstable and starts to behave weird after that - those ClassFormatError exceptions keep happening when we try to load the class again from the same jar that was updated, even though we use new instance of URLClassLoader and it happens in different app thread.
The app is running and compiled on Debian Squeeze 6.0.3/Java 1.4.2, migration is not within my power.
Here's a simple code that mimics app behavior and roughly describes the problem:
1) Classes for main app and per-client threads:
package BugTest;
public class BugTest
{
//This is a stub of "client" class, which is created upon every connection in real app
public static class clientThread extends Thread
{
private JarLoader j = null;
public void run()
{
try
{
j = new JarLoader("1.jar","SamplePlugin.MyMyPlugin","SampleFileName");
j.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
//Main server thread; for test purposes we'll simply spawn new clients twice a second.
public static void main(String[] args)
{
BugTest bugTest = new BugTest();
long counter = 0;
while(counter < 500)
{
clientThread My = null;
try
{
System.out.print(counter+") "); counter++;
My = new clientThread();
My.start();
Thread.currentThread().sleep(500);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
2) JarLoader - a wrapper for loading classes from .jar, extends Thread. Here we load a class which implements a certain interface a:
package BugTest;
import JarPlugin.IJarPlugin;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class JarLoader extends Thread
{
private String jarDirectory = "jar/";
private IJarPlugin Jar;
private String incomingFile = null;
public JarLoader(String JarFile, String JarClass, String File)
throws FileNotFoundException, MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
File myjarfile = new File(jarDirectory);
myjarfile=new File(myjarfile,JarFile);
if (!myjarfile.exists())
throw new FileNotFoundException("Jar File Not Found!");
URLClassLoader ucl = new URLClassLoader(new URL[]{myjarfile.toURL()});
Class JarLoadedClass =ucl.loadClass(JarClass);
// ^^ The aforementioned ClassFormatError happens at that line ^^
Jar = (IJarPlugin) JarLoadedClass.newInstance();
this.setDaemon(false);
incomingFile = File
}
public void run()
{
Jar.SetLogFile("log-plug.txt");
Jar.StartPlugin("123",incomingFile);
}
}
3) IJarPlugin - a simple interface for pluggable .jars:
package JarPlugin;
public interface IJarPlugin
{
public void StartPlugin(String Id, String File);
public void SetLogFile(String LogFile);
}
4) the actual plugin(s):
package SamplePlugin;
import JarPlugin.IJarPlugin;
public class MyMyPlugin implements IJarPlugin
{
public void SetLogFile(String File)
{
System.out.print("This is the first plugin: ");
}
public void StartPlugin(String Id, String File)
{
System.out.println("SUCCESS!!! Id: "+Id+",File: "+File);
}
}
To reproduce the bug, we need to compile a few different .jars using same class name, whose only difference is number in "This is the Nth plugin: ". Then start the main application, and then rapidly replace the loaded plugin file named "1.jar" with other .jars, and back, mimicing the hotswap. Again, ClassFormatError is to be expected at some point, but it keeps happening even when the jar is completely copied (and is NOT corrupt in any way), effectively killing any client threads which try to load that file; the only way to get out from this cycle is to replace the plugin with another one. Seems really weird.
The actual cause:
It all became sort of clear once I simplified my code even more and got rid of clientThread class, simply instancing and starting the JarLoader inside the while loop in main. When ClassFormatError was thrown, it not just printed the stack trace out, but actually crashed the whole JVM (exit with code 1). The reason is not as obvious as it seems now (it wasn't for me, at least): ClassFormatError extends Error, not Exception. Hence it passes through catch(Exception E) and the JVM exits because of uncaught exception/error, BUT since I spawned thread which caused error from another spawned (client) thread, only that thread crashed. I guess it's because of the way Linux handles Java threads, but I'm not sure.
The (makeshift) solution:
Once uncaught error cause became clear, I tried to catch it inside the "clientThread". It sort of worked (I removed the stacktrace printout and printed my own message), but the main problem was still present: the ClassFormatError, even though caught properly, kept happening until I replace or remove the .jar in question. So I took a wild guess that some sort of caching might be a culprit, and forced URLClassLoader reference invalidation and Garbage Collection by adding this to clientThread try block:
catch(Error e)
{
System.out.println("Aw, an error happened.");
j=null;
System.gc();
}
Surprisingly, it seems to work! Now error only happens once, and then file class just loads normally, as it should. But since I just made an assumption, but not understood a real cause, I'm still worried - it works now, but there's no guarantee that it will work later, inside a much more complicated code.
So, could anyone with deeper understanding of Java enlighten me on what's the real cause, or at least try to give a direction? Maybe it's some known bug, or even expected behavior, but it's already way too complicated for me to understand on my own - I'm still a novice. And can I really rely on forcing GC?