This is a kind of driving me nuts, I found some similar questions here on SO but I can't get it to work.
I have a multi project spring (web) project. It starts fine, but as soon as I want to query the db I get a
Nested in org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException:
Cannot create JDBC driver of class 'oracle.jdbc.OracleDriver' for connect URL 'jdbc:oracle:thin//server:1521:XE':
I tried many things: I made sure the ojdbc.jar is inside my project (not part of maven repo so I loaded it with gradle like
compile files('lib/websphere_apis.jar','lib/ojdbc14.jar')
in my sub (not web) or in my web project.
Which gets the jars inside war when I generate them with with gradle war
I tried adding the jars to the jettyRun configuration with
jettyRun {
additionalRuntimeJars = files('lib/ojdbc14.jar')
}
I'm a bit in doubt whether the files stmt is correct but still it doesn't work.
I also found on SO that I should put
providedRuntime files("$projectDir/../lib/ojdbc14.jar")
inside my webapp as a standard dependency but that still doesn't work for me. I have used postgres driver jars before which I could just include as a dependency.
With JDBC .jar files, if you are not careful about where you load the .jar on the classpath, you might get an error like what you are seeing. If you want to be sure, pass the .jar on the classpath as an argument to the main JVM that is calling the program. The reason is that you need to make sure the .jar class files are loaded in the "default JVM classloader". If you try to load JDBC .jars dynamically through other means ( perhaps even as OSGI) , or dynamically loaded by custom classloader like Tomcat has, then you could get class loader issues.
Related
This is a strange problem. I have an existing JEE project that is and has been in production on WebSphere 7. It is a multi-module EAR file. It has 2 WARs and 1 shared Java project. Most of it is Spring 4 based, but we have some web services we host using axis2 (1.5.4). This project does not use Maven. It does use a WebSphere deployment.xml (in the EAR) with the warClassloaderPolicy="SINGLE" and the classloader mode="PARENT_LAST". This controls the classloader policies for this EAR. All the jar files that the Java project and the WARs rely on are stored at the EAR level and referenced at the module level via the manifest files. That all works fine and has for several years.
Now I was trying to convert this project to a Maven project after all these years. Initially, I left the deployment.xml file settings as they always have been. But with these settings I was getting:
java.lang.VerifyError at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl "org.springframework.oxm.jaxb.Jaxb2Marshaller".
After much googling on this site and all around and trying 50,000 things, I tried one thing, which worked for most of the app. I switched the classloader mode to "PARENT_FIRST" and all of a sudden the WAR that exclusively uses Spring 4 worked. It started up without error and I was able to run it.
But, the other WAR which hosts the axis2 web services started getting the error:
org.apache.axis2.deployment.WarBasedAxisConfigurator <init> org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.NoClassDefFoundError: org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileUploadException
This class (org.apache.commons.fileupload.FileUploadException) is in both the compile and runtime classpath. In eclipse I can see it in the "Maven Dependencies" library that the m2e eclipse plugin creates from the POM files. I can also see this jar in the WebSphere runtime module classpath inspector (it shows up in there 3 times! Once under each WAR and once just in a list from the Maven repository location.)
One thing of note is that I've configured the project with a parent POM, where most of the dependencies are declared at the parent and then are inherited for each of the modules. In the EAR project, the POM is using the maven-ear-plugin with skinnyWars=true. However, it appears the skinnyWars directive is not respected when the m2e eclipse plugin deploys the EAR into the local WebSphere server (that is evident because I see these jars showing up in the classpath 3 times). But when I create an EAR using the Maven build, the EAR comes out correctly with each jar only showing up in the EAR one time.
This is my last hope to post something here and see if someone has an idea for something to try, otherwise I can't think of anything else to try.
Thanks...
Is there a particular reason you need to run with a single class loader for all the WAR modules, other than convenience? If not, you could rework the application in order to allow you to run PARENT_FIRST in the Spring WAR and PARENT_LAST in the Axis2 WAR.
If that's not an option for some reason, the path of least resistance might be to go back to PARENT_LAST and remove some libraries from the app or module. The VerifyError generally occurs if you're running with PARENT_LAST and have a library in the app that is also present in the server - in this case, the exception looks like it's coming out of JAXB, so you might want to see if simply removing JAXB (and perhaps JAXP, if present, since it's heavily used by JAXB) from the application resolves the issue with your default setup.
You could also stick with PARENT_FIRST and move the Axis2 jars to an shared library with an isolated class loader, associated with the app. An isolated shared library would make just the stuff in the shared library PARENT_LAST, so you can avoid the VerifyError and still get PARENT_LAST for Axis2. The issue in the PARENT_FIRST case appears to be because you're picking up WebSphere's copy of Axis2 but somehow have a dependency inserted from your app's copy - the failing class load is occurring in a server-level loader, so it doesn't see the copy in your app.
Can anyone explain how Spring decides where to look for resources when one uses the ResourceLoader.getResource(...) method?
I am having a problem with a multi-module maven application built using Spring Boot whereby in my integration tests my code is able to find resources using resourceLoader.getResource("templates/") or even resourceLoader.getResource("classpath:templates/"). So far so good...
However, when the module is eventually packaged into the executable JAR and run with embedded Tomcat the resources can no longer be resolved. I also tried resourceLoader.getResource("classpath*:templates/") with no success.
What I find concerning is that when I add a logging statement to output the URL being used in the search i get a path to one of the other modules in the project (not the one that actually contains the resource in question). E.g: jar:file:/Users/david/exmaple/target/spring-boot-0.0.1-SNAPSHOT.jar!/lib/module1-0.0.1-SNAPSHOT.jar!/templates/ whereas I believe the resource is in jar:file:/Users/david/exmaple/target/spring-boot-0.0.1-SNAPSHOT.jar!/lib/module2-0.0.1-SNAPSHOT.jar!/templates/
The resource loader was obtained from an Autowired constructor param.
Thanks in advance for any hints.
Edit
Just in case it isn't clear or is of importance, my integration tests for the module in question aren't aware of the other module. I have module1, module2 and a spring-boot module which has dependencies on module1 & module2. Essentially, when I run the integration tests for module 2 the classpath isn't aware of module1 - so I suspect that this has something to do with why it works in the tests.
When you use classpath: or classpath*: prefix, internally, this essentially happens via a ClassLoader.getResources(…) call in spring.
The wildcard classpath relies on the getResources() method of the underlying classloader. As most application servers nowadays supply their own classloader implementation, the behavior might differ especially when dealing with jar files. A simple test to check if classpath* works is to use the classloader to load a file from within a jar on the classpath: getClass().getClassLoader().getResources("<someFileInsideTheJar>"). Try this test with files that have the same name but are placed inside two different locations. In case an inappropriate result is returned, check the application server documentation for settings that might affect the classloader behavior.
Do not use classpath: form as you have multiple classloader locations of templates/ .
Refer to: resources-classpath-wildcards
I have a spring boot app and I start it with -Dloader.path=. One of the jar files is hive-exec.jar. This has a jar file bundled called minlog-1.2.jar. If I specify this file in -Dloader.path, I get an error,
java.lang.IllegalStateException: Unable to open nested entry 'minlog-1.2.jar'. It has been compressed and nested jar files must be stored without compression. Please check the mechanism used to create your executable jar file
at org.springframework.boot.loader.jar.JarFile.createJarFileFromFileEntry(JarFile.java:378)
at org.springframework.boot.loader.jar.JarFile.createJarFileFromEntry(JarFile.java:355)
at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:341)
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:108)
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:92)
at org.springframework.boot.loader.PropertiesLauncher.getClassPathArchives(PropertiesLauncher.java:445)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:60)
at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:564)
However, if I copy this file into a folder and add that folder in -Dloader.path, I don't get any error.
What am I missing?
Thank You,
I am trying to manage the database driver as external jar instead of a project's maven's dependency. The application use the JPA framework, and we wanted to be able to switch from one SQL-database implementation from one environment to another (for example, H2 in DEV, Oracle in production). I had to manage the h2-database-driver jar as an external dependency. While loading it with the "-Dloader.path" command line option, I came accross he same problem as you described.
Viewing the org.springframework.boot.loader.jar.JarFile source code, the class manage an folder-entry and a jar-entry differently.
The method getNestedArchives seems to invoke the createJarFileFromFileEntry method which throw this exception.
There must be a good reason for it, if someone know about it, any comment is welcomed!
When loading jar dependencies from a directory, the java.util.jar.JarFile constructor is used instead and does not seem to throw any exception...
In the createJarFileFromFileEntry method, instad of throwing an exception, wouldn't it be possible to only have a log.warn and not throw an exception?
I am using activejdbc 1.4.9. I created one jar (using maven) which has two ActiveJDBC Model Classes. I added the jar to the application. Application has three more model classes. When I compile and try to run the application (gradle based), activejdbc is instrumenting only 3 classes which are in application but not instrumenting the classes which are in jar. When I try to write the data into the two models which are in jar, It is throwing exception as
org.javalite.activejdbc.DBException: Failed to retrieve metadata from DB. Are you sure table exists in DB ?
Now I have certain doubts. Please help me to resolve and understand few things.
How instrumentation happens ?
When we create a jar, will it include instrumented classes ?
Why it is throwing this error ?
It is throwing this error in case classes have not been instrumented. This means that before placing your model classes into a jar file, you need to instrument them. Does not matter which build method you use though. This http://javalite.io/instrumentation explains what is instrumentation and how to do it. Instrumentation does not create jars, it merely adds some byte code into your classes. In all scenarios you need:
Write code :)
Compile
Instrument
after this, you can do any of the following:
run app using class files in the file system
package class files into jar file and use that on your classpath
package jar file into a larger app (WAR, EAR, RAR, etc.) and deploy your app
making sense?
I'm working to migrate an application from Oracle Application Server to JBoss EAP 6.1. I have most things working but I am getting one error that I haven't been able to figure out:
13:27:29,743 ERROR [com.myproj.db.dao.myDao] (Thread-164) Get Prepared Statement:
java.lang.ClassCastException:
org.jboss.jca.adapters.jdbc.jdk6.WrappedPreparedStatementJDK6 cannot be cast
to oracle.jdbc.internal.OraclePreparedStatement
I have Oracle set up as a module in JBoss for connection pooling using ojdbc6.jar (and it works for other parts of the application), but for the one part of the application that uses an OraclePreparedStatement, it gets the error.
I did make certain that there is no ojdbc6.jar file in the WAR file. The only one in JBoss seems to be inside of the module.
I did try changing the OraclePreparedStatement class to oracle.jdbc.OraclePreparedStatement, but the results are the same.
I did try running with TRACE on for logging to see where classes were loading from. OraclePreparedStatement was loaded from the module with the exception of this line:
4:31:40,583 TRACE [org.jboss.modules] (Thread-84) Finding class
oracle.jdbc.OraclePreparedStatement from Module "deployment.myProj.war:main" from
Service Module Loader
Here's a link to an excerpt of the log - basically just the lines related to OraclePreparedStatement.
I have confirmed that there is no ojdbc6.jar (or any Oracle related jars) in the WAR file, and there is no OraclePreparedStatement class inside of the WAR file either.
I do have the module listed as a dependency in my JBoss deployment structure xml file.
Anyone have any ideas?
From looking at the javadoc I would guess that org.jboss.jca.adapters.jdbc.jdk6.WrappedPreparedStatementJDK6 is wrapping the underlying Oracle JDBC driver.
org.jboss.jca.adapters.jdbc.jdk6.WrappedPreparedStatementJDK6 has a method to get the underlying statement. Perhaps you should try something like the following:
WrappedPreparedStatementJDK6 statement = ...
OraclePreparedStatement oracleStatement = (OraclePreparedStatement)statement.getUnderlyingStatement();