ClassNotFoundException in Java Agent Instrumentation premain - java

I read https://www.baeldung.com/java-instrumentation and I'm trying to instrument the doService method in org.springframework.web.servlet.DispatcherServlet, which is part of the Spring Boot framework, i.e. spring-webmvc.jar.
This is the way I start my spring boot application:
java -javaagent:agent.jar -jar myapp.jar
I understand my agent's pom.xml should package/include the javassist dependency but I don't expect the agent should package/include the jar spring-webmvc.jar containing the class org.springframework.web.servlet.DispatcherServlet, as it is already packaged and contained in myapp.jar
In the premain of the agent, when I try to instrument and load the class org.springframework.web.servlet.DispatcherServlet by using forName, it throws the ClassNotFoundException.
How should I instruct the agent to load it from the myapp.jar ?
Thank you!
try {
targetCls = Class.forName(className);
targetClassLoader = targetCls.getClassLoader();
LOGGER.log(Level.INFO, "Successfully obtain target class {0} and its classloader using 'forName' with class loader {1}", new Object[] {className, targetClassLoader.toString()});
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Class {0} not found with Class.forName. {1}", new Object[] {className, ex.getClass().getCanonicalName()});
}

If you are new to Java instrumentation and following this post, note that manually invoking forName is not necessary in the example. What you can do is to register the transformer in premain and then in transform method, check for your target class name and start the instrumentation as instructed in the link. Happy coding!

Related

Start spring-boot application with classLoader

I'm searched a lot for a solution for my case, basically i will start/run my spring boot application in other spring boot application.
How i tried do:
String[] args = { "-Dspring.profiles.active=development",
"-Dspring.config.location=config/example-db-development.properties,config/example-custom-development.properties",
"-Dloader.path=test/lib" };
File fatJar = new File("D:/spring-boot-example/test/spring-boot-example-api.jar");
ClassLoader classLoader = new URLClassLoader(new URL[] { fatJar.toURI().toURL() });
Class<?> mainClass = classLoader.loadClass(getMainClassName(fatJar));
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { args });
private static String getMainClassName(File fatJar) throws IOException {
try (JarFile jarFile = new JarFile(fatJar)) {
return jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
}
}
This started the example project, however, I need to add some dependencies of the example project to the project that should start the same.
And I'm still having problems for springboot to be able to create beans, for example:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vendaPDVControllerImpl' defined in URL [jar:file:/D:/dsv-git/dsv-java/pdv-prototipos/spring-boot-integrador-testes/test/spring-boot-integrador-api.jar!/BOOT-INF/classes!/br/com/sysmo/integrador/api/impl/VendaPDVControllerImpl.class]: Post-processing of merged bean definition failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [br.com.sysmo.integrador.api.impl.VendaPDVControllerImpl] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader#31f924f5]
I do not want to have to add dependencies of the sample project on the project that should start it, and I already looked in the stack overflow for solutions, but found none that solves my problem.
I'd like something like this, but from the classLoader, or another solution that makes it possible to start my application without adding its dependencies to my project:
java -jar -Dspring.profiles.active=development -Dspring.config.location=config/example-db-development.properties,config/example-custom-development.properties -Dloader.path=lib example-api-1.00.00.000.jar

path of EJB class in lookup function on javaEE

I want to inject the content of EJB class to object variable with lookup function but not found the path. Following is my cod in javaEE:
PrintWriter out = response.getWriter();
out.println("this is the flight details:.....");
try{
Context context = new InitialContext();
Object ob = context.lookup("java:global/ejb1/SourcePackage/FlightService!com.airline.service.FlightService");
fs = (FlightService)ob;
}
catch(Exception e){
out.println("not found path");
}
and my structure of project is :
First of all I think is better to understand what wrong with annotation, cause injecting bean is simpler and controls by container not you. Lookup is a choice only when you are tryin to get access to ejb from another jvm.
Secondly your path is wrong. You use module-name instead of app-name and Source package is a IDE specific thing. Path in JNDI is based on built jar file.
As described in EJB specification global name creates by following pattern
java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]
where in your case
app-name normally ear name
module-name normally EJB jar name (in
your case ejb1)
bean-name is simple name of class with annotation
Stateless, Statefull, Singleton.
interface name is canonical name of implemented interface

Splitting resources.groovy (Grails 2.5) to make it modular

resources.groovy of my Grails project is growing, so I am thinking of splitting it in some logical files that will be easier to mantain. After reading some questions, blogs, i got to know about importBeans or loadBeans. This works well only when application is run using grails run-app. However we I create a war and deploy it on JBoss, the custom bean files are not accessible.
Also tried below with no luck - mentioned here -
Load spring beans from custom groovy files in grails app
grails.war.resources = { stagingDir, args ->
copy(todir: "${stagingDir}/WEB-INF/classes/spring") {
fileset(dir:"grails-app/conf/spring") {
include(name: "datasourceDefinitions.groovy")
exclude(name: "resources.groovy")
}
}
}
I have added datasourceDefinitions.groovy in grails-app/conf/spring.
Please help.
The problem is due to the Spring bean configuration files are moved into the folder "WEB-INF/classes/spring/"(make sure the file is packaged in the.war) inside the WAR file. As what I did was locate the resource path in resources.groovy.
def loadFromFile = { name ->
importBeans("file:grails-app/conf/spring/"+name)
}
def loadFromWar = { name ->
def resource = application.parentContext.getResource("WEB-INF/classes/spring/"+name)
loadBeans(resource)
}
def loadResource = application.isWarDeployed() ? loadFromWar : loadFromFile
loadResource "datasourceDefinitions.groovy"
loadResource "anotherBean.groovy"

Spring Batch CommandLineJobRunner can't find .xml configuration file

I'm a total beginner in Spring Batch Framework, and I found easily understandable codes from http://www.javabeat.net/introduction-to-spring-batch/ to use as a learning tools. I have my project set up in Eclipse similiar to the codes from the page, it looks like this :
and the code executes the jobs in fileWritingJob.xml using CommandLineJobRunner like so :
package net.javabeat.articles.spring.batch.examples.filewriter;
import org.springframework.batch.core.launch.support.CommandLineJobRunner;
public class Main {
public static void main(String[] args) throws Exception {
CommandLineJobRunner.main(new String[]{"fileWritingJob.xml", "LayeredMultiThreadJobTest"});
}
}
and it runs as expected with no problem. But when I move the fileWritingJob.xml to another dir (still under the project dir) it doesn't run. I've tried changed the filename arguments at the CommandLineJobRunner method using relative and full path but it still doesn't run. For example, if create a directory under the project directory (same level as config) named jobs and put the xml there then pass the filepath to CommandLineJobRunner like this:
CommandLineJobRunner.main(new String[]{"/jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
or this
CommandLineJobRunner.main(new String[]{"../jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
it doesn't work.
But when I tried creating a subdir under the config directory and put the fileWritingJob.xml there, like this
CommandLineJobRunner.main(new String[]{"configsubdir/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
it runs. It's as if the CommandLineJobRunner only checks the config directory.
I'm running out of ideas, can anyone help me?
UPDATE : After digging around a bit, thanks to Michael Minella's suggestion about ClassPathXmlApplicationContext I am able to put the xml wherever I want. I also consulted to this page Spring cannot find bean xml configuration file when it does exist and http://www.mkyong.com/spring-batch/spring-batch-hello-world-example/
So what I do now is declaring a new context by using ClassPathXmlApplicationContextand then run it using job launcher, here is how :
public static void main(String[] args) {
String[] springConfig =
{
"file:/path/to/xml/file"
};
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("JobName");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status : " + execution.getStatus());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Done");
}
Thank you very much for all your inputs!
A little detail around what is happening when you pass in the path to the xml based job definition to the CommandLineJobRunner. All we do is we pass that string to the constructor of ClassPathXmlApplicationContext. Because of that, it is expected that the xml file for the job definition be on the application's classpath. I can't tell from your project screen shot how you are building the project so I'm not sure if the config directory is on your classpath or not. However, if it is on the classpath and lives at the root of it, I'd expect you to be able to pass the path to the fileWritingJob.xml as "/config/fileWritingJob.xml".
The source for this class can be helpful when debugging this type of issue. You can find the source code for the CommandLineJobRunner here: https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java
You can specify the job path relative to your config directory. For example, if fileWritingJob.xml is in config/jobs/ directory, then in you can execute the job as follows:
CommandLineJobRunner.main(new String[]{"jobs/fileWritingJob.xml", "LayeredMultiThreadJobTest"});
Likewise, if the job configuration file is outside of the config directory, you can write:
CommandLineJobRunner.main(new String[]{"../fileWritingJob.xml", "LayeredMultiThreadJobTest"});
You can specify an absolute path for locating the job.

Calling an EJB3 from local tomee

I've spent most of my day on something that supposedly is very simple on EJB 3 in Tomee.
I have a Test.jar in the apps folder, and in it, there is a stateless bean with a method called testMethod().
Bean: TestBean.java
Remote Interface: Test.java
In web application TestClient.java:
public String testMethod(){
try {
InitialContext ctx = new InitialContext();
Test test = (Test) ctx.lookup("Test");
test.testMethod();
//System.out.println("Output from JavaClient");
} catch (NamingException e){
e.printStackTrace();
}
}
and a JSP, which calls the TestClient class for execution.
I get the following error: javax.naming.NameNotFoundException: Name [Test] is not bound in this Context. Unable to find [Test].
I have tried TestBean/remote in the context object with similar results.
Both the jar and the war are running in the same tomee container. If somebody can shed some light on what I am doing wrong, it will be greatly appreciated.
the correct jndi name is in the logs (look for "Jndi(").
will likely be java:global//TestBean!Test or something like that

Categories