How to identify which class is calling a specific method? - java

Let's assume that we have an abstract class with a method that prints a WARN log entry (WARNING: Cannot set header. Response already committed), this method is being called by class X lots of times (it is flooding the logs).
Based on the log entry that was generated from the Application Server, I have managed to identify the abstract class and found its jar (using jarscan), the JAR is an OOTB Component of the application server so it is not supposed to be modified in any sense. I have hacked the JAR and introduced a line within the method that generates the log entry:
new Exception().printStackTrace()
This approach should give me the stack trace to identify class X.
However, I don't know how to reproduce this error in my test environment, there are a lot of projects that I don't have in my workspace and I can't just check hundreds of classes to see which one is setting something into the response object, I have tried to find a match between the log entries timestamps and Selenium test reports that are running against the test environment but it is not showing up in the logs.
Question: What would be a good troubleshooting approach to identify Class X without any intrusive changes on the environment that presents the issue?

If you cannot use debugger because of your environemnt specific, you can investigate classes loaded into your server's JVM and find classes that inherit from your abstract class.
Run jvisualvm and connect to your server's JVM, then go to OQL console in jvisualvm and run such query:
select heap.findClass("com.xyz.my.AbstractClass").subclasses()
This will find all subclasses of your abstract class currently loaded.

public String getMethodName(final int depth) {
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
return ste[depth].getMethodName();
}
Usage:
public void doSysOutTest() {
String getMetNameFunc = getMethodName(1);
String callingMethod = getMethodName(2);
System.out.println(getMetNameFunc);
System.out.println(callingMethod);
}
Output:
getMethodName
doSysOutTest
To get more information out of the stack you could also use these methods:
ste[depth].getClassName()
ste[depth].getFileName()
ste[depth].getLineNumber()
Take a look here: http://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html

Related

How to efficiently add method name to Java logging message without typing it in manually?

In my Java application, I would like the logs to reflect the calling method name in the message. So that a the following code:
void foo(){
logger.info("some message");
}
would result with log message:
2020:10:10T10:10:10 thread class #foo some message
I am using Logback and SLF4J, and I understand that I can use message template.
To my understanding, this uses reflection and traveling up the call stack, and is a performance hit my team has had issues with in the past.
As an alternative, I looked into AOP, such as AsepectJ. As far as I can find, the calling context is not supplied in any of the AOP libraries. A simple before/after/wrap option won't reveal the identity of the method in which the call is made.
I'm looking for a way to inject a logging aspect using annotations. Something like:
#LogMethodName
class enhancedLoggingClass{
void foo(){
logger.info("some message");
}
}
And in some code/DSL I would write something like:
filter Methods with LogMethodName attribute OR inherited attribute from class
for each method:
find call to Logger(String s, *)
change to Logger(method.getName() + s, *)
In the past, in a C# 2.0 project a colleague tried out writing "shadow" code in which we could do anything. But this bypassed the tooling and made debugging not work, etc. So that was ditched.
Any suggestion are welcome.

Tomcat update java file at runtime

I am building a dynamic Web Project (in Eclipse with Tomcat as server) using servlets and JSPs. The general purpose of the project is to let the user solve small code problems. In order to do that I take a method written by the user and use it to build a java file that I can run via Reflection. The problem I can't seem to figure out is that Tomcat (or Eclipse?) does not update the file at runtime. So when I create the file using the code of the current user and try to compile it, my program always executes the file as it was when I started the server using the code of the previous user. How can I tell it to update the file before running it?
Edit:
That's how I create the file:
public boolean writeFile() {
try {
PrintWriter writer = new PrintWriter(relativePath + "src\\testfiles\\TestFile.java");
writer.print(content);
writer.close();
return true; }...
Here I call the writer and try running the file:
FileWriter writer = new FileWriter(content);
if(writer.writeFile()){
Class<?> TestFile;
Method m;
try {
TestFile = cl.loadClass("testfiles.TestFile");
m = TestFile.getDeclaredMethod("testSolution");
m.invoke(null);
Thanks in advance!
Ok, it's now clear what the issue is. Your issue is not with Tomcat not reloading the file, but with the classloader not reloading the class.
Normal classloaders will only load a class once, and keep it cached forever. The only way for a class to get unloaded is by its classloader being garbage collected. To reload a class you either have to use a different classloader each time (with the previous one getting garbage collected or you'll run out of memory), or to have a custom loader thar doesn't cache.
See this article for an implementation of a custom classloader that does what you want.
You could theoretically just have a new class each time (by changing its name on each save) but you'd eventually run out of memory.
Maybe the easiest way is to instantiate a new classloader in the method itself, load a class, run the method on it, and don't keep any other references to the loader or the class. That way, you'll get a freshly loaded class each time, and the old instances of both classes and loaders will get garbage collected.
UPDATE: I was operating under the assumption that you already know how to compile a class at runtime but, based on the comments, that's not the case.
A classloader can, of course, only load a compiled class, so a source directly is not very useful.
Java internally provides a a compiler interface under javax.tools.JavaCompiler, but it's not easy to use and requires a different handling of Java versions before and after Java 9. So it is much easier to use a library like jOOR that hides the gory parts:
Class clazz = Reflect.compile("com.example.Test",
"package com.example;" +
"public class Test {\n" +
" public String hello() {\n" +
" return \"hello\";\n" +
" }\n" +
" }")
.type();
Instead of type() to simply get the class, you can actually keep using jOOR's fluent reflection API to trigger the methods on the generated class or whatever it is you'd normally do via regular reflection.
For direct JavaCompiler usage, see e.g. this or, even better, jOOR's source code.

How to get default application name in cli?

I want to create a framework that shows the application name on statup. Targeting command line interface applications.
Question: how can I get such an application name in a generic way?
Eg spring offers a property, but which is not set by default:
#Value("${spring.application.name}")
private String appname;
And I don't want to set that property explicit. Looking for some kind of "default application name".
In a Java EE container there is also the following option:
String myApplicationName = (String) initialContext.lookup("java:app/AppName");
But how about CLI apps? How can I get some kind of generic application name?
The closest you can get, if I interpreted correctly your question, is to:
find which class is running public static void main(String [] args) method
get its simpleName
store aforementioned name into a system property
and in order to do so, you have two options:
call Thread.currentThread().getStackTrace(), and inspect its tail element. But this has to be executed in the main thread as well, otherwise you wont retrieve the correct StackTraceElement;
call Thread:getAllStackTraces(), and parse the entire map to identify the main Thread, get the corresponding value, and pick its last StackTraceElement
Once you have StackTraceElement, you can call StackTraceElement:getClassName() which will return something like
scala.tools.nsc.MainGenericRunner
Split the string, save it into a system property, and you're good to go.
Hope it will help you.

Java - Hide system output when testing

I am not sure if it is possible but if so how do I do it? I have a project which contains another 2 projects as dependencies. The parent project is only used for testing purposes (client server app). When I am testing I have a difficulty reading through my testing output because of the large amount of output the client and the server projects have. I am trying to find a way hide from the console all the output(printf()) of my sub-projects so that I can only see my testing output. Is there a way to do so?
For testing I am using JUnit.
Thanks
You should use Java Logger API (or Log4J) instead of using System.out.print directly, sou you could disable specific loggers during executions of your tests.
If you can't change legacy code to use Logger API, there are two options:
Option 1:
Create a PrintStream decorator class like this pseudo-code:
public class FilteredPrintStream extends PrintStream {
private final PrintStream stream;
...
#Override
public void print(String str) {
if (notCalledBySubproject()) {
stream.print(str);
}
}
// override other methods too
}
Then you set default output: System.setOut(new FilteredPrintStream(System.out));
To find method caller (to create notCalledBySubproject method), see How do I find the caller of a method using stacktrace or reflection?
Option 2:
Use Logger API in your test code, so you can redirect your output to a file, for example, then you ignore console output and see the file generated by your tests.
It is not a perfect solution nor good coding practice but you could add a class like this
public class SystemOutput
{
public static final boolean DO_PRINT = true;
public void printf(String format, Object... args)
{
if(DO_PRINT)
System.printf(format, args);
}
}
and use Find and Replace once to replace "System.out.printf" with "SystemOutput.printf" in every class needed. Because both methods have the same declaraction only this has to be changed. When you want to block the output you can just set DO_PRINT to false.
Eclipse for example provides a search tool which can find and replace a certain string in every .java file in a project. (Strg + H under the File Search tab)
of course it is also possible to call System.setOut() with your own subclass of PrintStream, that overrides the printf() method to only print when a certain boolean value is true.
why do you need console to run unit tests? ignore it. if your tests passes you got 0 status code or green bar (IDE or jenkins). any error stack trace you can find in e.g. maven log tests results. just ignore the std output
another thing: using console in your application is usually bad idea - avoid it. use logging framework instead (it will let you control the destination and level of logging). use your IDE and refactor - replace all calls to printf with log.debug or with you own wrapper. if your IDE doesnt support it then use some regex and try replace-all
if you want to get rid of all the output you can redirect stdout to /dev/null or change output stream in java. but it's not a proper solution

Oracle BPM Human Task Comments Callback Errors When Instantiating AppModule in Called Class

Oracle BPM Version 11.1.1.7. In a Humantask.task, Events tab, Content Change Callbacks section, I have entered the fully qualified class name of a class that implements NotesStore and the addNote and getNotes methods.
The class uses public methods in an AppModule to write and read comments using our custom table and these methods were well tested during development using the the BC tester and a temporary main in the callback class.
The project is compiled to a jar and placed in the BPM project's SCA-INF/lib folder, then the SCA and related ADF human task forms are deployed.
When a comment is made in the out of box human task comments section during a process instance, the class is called, but an exception occurs in the getNotes method at the line the AppModule is created:
java.lang.ClassCastException: oracle.jbo.common.ampool.PoolMgr
In the class, the AppModule is created as so:
AuditModule service = (AuditModule)Configuration.createRootApplicationModule("com.co.modules.AuditModule", "AuditModuleLocal");
I've tried adding a web.xml config file to the SCA BPM project with a filter as discussed in this post (last answer). This discusses triggering the ADF Context initialization, but I'm still getting the error.
The question is, how can I use a call back from a human task to call a method that uses AppModule public methods to do the DB work? Oracle's documentation is very sparse in this area (29.11.1).
UPDATE
Turns out that the stack trace shows that it is having problems looking up the data source name and is actually throwing a JBO error. If anyone runs in to this, check the stack trace for other issues.
UPDATE2
Finally got this to write task comments into the custom comments table. It turns out it doesn't seem possible to use an AppModule/Model approach in a comments callback class as there appears no way to initiate the needed ADF context when the class is called. By rewriting the class to access the DB directly in code the comment callback class does write the table. But, I am getting the same error as this post. Namely:
Exception invoking method from XML data control. Cause:oracle.bpel.services.workflow.client.WorkflowServiceClientException: java.rmi.UnmarshalException: cannot unmarshaling return; nested exception is:
Supplemental Detail java.io.IOException: Error: Unexpected type encountered in writeExternal oracle.bpel.services.workflow.client.WorkflowServiceClientException: java.rmi.UnmarshalException: cannot unmarshaling return; nested exception is:
java.io.IOException: Error: Unexpected type encountered in writeExternal
I suspect this is an Oracle framework issue as the types that are passed back are from the NotesStore implementation which are all passed back to the framework:
public class CommentsCallback implements NotesStore, Serializable...
public List<CommentType> getNotes(Task task)
Has anyone solved this? Full stacktrace at:
https://community.oracle.com/thread/3638940
After discussion with Oracle, the key to avoiding the unexpected type error is to use an ObjectFactory to populate the CommentType object. While we took a different approach ultimately, the below code was provided by Oracle as an example and might help someone trying to do this:
import oracle.bpel.services.workflow.task.model.ObjectFactory; 
import oracle.bpel.services.workflow.task.model.CommentType; 
import oracle.bpel.services.workflow.task.model.IdentityType; 
...
ObjectFactory factory = new ObjectFactory() 
CommentType commentType = factory.createCommentType(); 
IdentityType updatedBy = factory.createIdentityType(); 
updatedBy.setId("some user"); 
updatedBy.setType(IWorkflowConstants.IDENTITY_TYPE_USER); 
updatedBy.setDisplayName("some user display name"); 
commentType.setUpdatedBy(updatedBy); 
commentType.setComment("some comment"); 
...set the rest of the comment fields as necessary... 

Categories

Resources