I am using liferay 6.1 and working on Eclipse IDE.
An EJB project which i copied from another PC (which uses JDK 1.7 same as mine).
I am compiling this EJB project and exporting it as a jar and using it on my liferay portlet.
so basically i call the ejb method. surprisingly, i can call all the methods which was already there. but now when i add new method on my remote interface like this:-
#Remote
public interface PreExaminationRemote {
public String dummy();
}
Implementation class
#Stateless
public class PreExamination implements
PreExaminationRemote,PreExaminationLocal{
public String dummy(){
return "works";
}
}
and call it from controller of my portlet it will simply throw an exception of method not found.
Exception in thread "liferay/scheduler_dispatch-1"
java.lang.NoSuchMethodError:
com.test.PreExaminationRemote.dummy()Ljava/lang/String;
I am using ant to build the jar file.
1. I tried ant clean.
2. I tried to clean the ejb project
3. I changed the workspace
nothing seems to work.
I'd expect, without fail, that this exception shows up when you have outdated code around. This might be the application server's cache, duplicate code (e.g. two different jars on the same classpath, with the same code in different versions) or locked files that couldn't be overwritten.
Search through the available classpath, don't forget appserver-globals, your own WEB-INF/lib and the appserver's temp and work directory before redeployment. To work around locked files (e.g. under Windows), reboot, redeploy and check if it still fails to work.
I don't see any other explanations for this behavior.
Related
Short Question
I have the same class (fully qualified com.example.pkg.cls.ClassName) in a jar and my web application code base. When my application loads, I want to load the class in my Web application instead of the one at the jar in classpath.
How should I do that?
Long Question
I have a situation like this here:
I have a web application with a JAR A as a dependency. The jar is a third party jar (some Amazon SDK). JAR A has a dependency on JAR B (some commons-lang).
Recently I upgraded the Web application to run Java 11 from Java 7. There is some bug in JAR B which is failing a code flow (specific to Java 11, tries to parse the java.version string). I have already checked for different versions of JAR A which might fix the problem but it doesn't. Infact, JAR A is deprecated and is no more available.
The part that is failing in JAR B is a toString method and in JAR A is a log statement. I am totally ok if that toString method doesn't return anything or returns a blank String.
After trying multiple solutions over days, I have been suggested to do this:
1 - Write a class with the same fully qualified class name as the failing class in B, copy the code and change the toString method.
2 - Load the class explicitly at startup, so that when the API is hit my class is already loaded over the class inside JAR B.
I have two questions here:
1 - Is there a problem with this approach?
2 - How can I load a class in my own project. Can anyone provide a code sample for this.
I'm using Equinox Transforms to replace one class with a custom version of it on the classpath. The transforms mechanism seems to be working properly, and I return an InputStream of the custom class from public InputStream getInputStream(InputStream inputStream, URL transformerUrl) of my transformer class.
But the loading of that class then results in a ClassFormatError with message Truncated class file. The only thing I can imagine causing this is a mismatch between Java versions, but I've done everything I know how to do to eliminate that as a source of the problem, to no avail.
I removed all but one JDK from Eclipse in the Installed JREs preference. I made sure all the plug-ins involved have the same Java version for their execution environment and the JRE on the build path is specified with the same execution environment. Target and product execution environments are defined the same also. I did a clean all in the workspace and re-launched eclipse and my runtime workbench many times, with -clean. After all this, I still get the error.
What else could it be if not Java versions causing this error? The Equinox Transforms page says it can be used to transform class resources. Has anyone actually done that?
there is a more standardized way to replace a class in osgi, through a WeavingHook. This hook should be registered as a service, and have the possibility to dynamically enhance a class.
See the WeavingHook Javadoc or a concrete example with Aries Proxy, which dynamically create proxies with the help of asm (WovenProxyGenerator).
Jboss-allclient.jar and jboss-logging.jar have a class org.jboss.logging.Logger , where the methods defined inside the classes are different but the package structure is same for both the classes. Due to which i have got an exception on deployment.
Exception
NoSuchMethodException of getMessage()
This is because, getMessage() method is present in one class alone. Unfortunately, it picks the wrong class and throws an exception.
Note :
This is working in tomcat 7 (windows and linux version) and tomcat8 (Windows)
Not working in tomcat 8 (Linux version).
JRE version is 8
Those two jars needed for my application.
In Tomcat 8 the sequence of loading jars within a single war is not guaranteed. Before it was alphabetical.
It was reported as a bug to Apache, but they claim it's a feature ;) Check https://bz.apache.org/bugzilla/show_bug.cgi?id=57129
One of the devs has come up with a workaround, but I have not tried it. You can have a look on https://github.com/openwide-java/tomcat-classloader-ordered
Good luck!
I have two Eclipse plugins:
plugin-1: provides a package in .jar to other plugins. (a Java Wrapper for a C++ library) This plugin was created by clicking File->New->Other->Plug-in from Existing JAR Archives.
plugin-2: has the native library .so for plugin-1 (Bundle-NativeCode directive is in MANIFEST.MF) and instantiates a class from plugin-1
(I actually tried putting the .so in plugin-1, but I cannot seem to load the library, even with the Bundle-NativeCode directive in the plugin-1 MANIFEST.MF, outside of the plugin project that contains the .so, so I guess I have to bundle the .so with any plugin that uses plugin-1.)
I am running a JUnit tests from plugin-2 which instantiates MyClass from plugin-2 which, in turn, instantiates MyLibraryClass from plugin-1. MyClass successfully loads the native library and instantiates MyLibraryClass without an UnsatisfiedLinkError or other exception being thrown from either the loading of the native library or from instantiating MyLibraryClass. I am not running a plugin in this case -- just the JUnit tests.
When I run plugin-2 (using a product configuration) and instantiate MyClass, the native library loads fine but I get an UnsatisifiedLinkError when MyClass instantiates MyLibraryClass. In this case, I believe the library is being loaded based on the output I get from using the class described in the posting How do I get a list of JNI libraries which are loaded?
NOTE: I'm using Eclipse 3.6.1.
Here is a code sample that shows the essence of what I'm trying to do:
package com.mylibrary;
import com.external_library.MyLibraryClass;
public class MyClass {
public static void loadLibrary() {
// Without Bundle-NativeCode in MANIFEST.MF I get
// "java.lang.UnsatisfiedLinkError: no mylibrary_java in java.library.path"
System.loadLibrary("mylibrary_java"); // Loads libmylibrary_java.so.
// Works fine from JUnit Test
// When I run the plugin, I get an UnsatisfiedLinkError:
// "java.lang.UnsatisfiedLinkError:
// com.external_library.MyLibrary_javaJNI.new_MyLibraryClass__SWIG_3()J"
MyLibraryClass instance = new MyLibraryClass();
}
}
I have replicated your setup and I get the same exception.
The problem could be solved by:
add the native library to plugin-1
add the Bundle-NativeCode directive to plugin-1's Manifest
load the library in the static constructor of plugins-1's Activator (you can write one and add it to the plugin)
Some other possible sources of errors:
Be aware that the package path, the class name and the method signatures should never be changed for any class with native bindings. Otherwise JNI would not be able to find the native counterpart and you get an UnsatisfiedLinkError. In your import directive you specified the following classname com.external_library.MyLibraryClass, but your error message has a different classname com.external_library.MyLibrary_javaJNI. Check for these sources of errors.
Some additional explanations:
A JUnit test in contrast to an JUnit plugin test starts no OSGi environment. Therefore you have a plain Java application with an ordinary JUnit test. If your native lib and your application are contained in the same folder (top level) the native lib will be automatically found on windows. If that is also true on UNIX systems, this would be an explanation why your JUnit test is successful. If it lies in a different folder, you have to specify the Java Library Path for an ordinary Java application.
EDIT by MrMas:
Modify plugin-2 so it doesn't depend on plugin-1 by adding the .jar file to plugin-2.
Copy the .jar file into plugin-2. I put it in the same directory as the .so.
Add the jar to the project via: Project->Properties->Libraries->Add Jar
Add the jar to the class path via plugin.xml->Runtime->ClassPath section->Add
Export the packages from the Jar (if they're needed by downstream plugins)
Remove the dependence of plugin-1 from the plugin.xml->dependencies tab
Now you can load the library with a System.loadLibrary and use the classes from within the plugin and from another plugin.
I chose not to modify plugin-1 because it was created as a plugin from an existing jar to which I couldn't discover how to add an Activator. I instead chose the path of adding the .jar to plugin-2. See Adding jars to a Eclipse PlugIn for additional discussion.
Bundle-NativeCode is an OSGI-tag. This means only OSGI classloaders are using it. In my case, I had an E4-RCP application. One plugin contained the Java class. The native code, however, I put into a fragment.
When loading and looking for a library, the OSGI classloader has a list of fragments (according to the naming of the structure involved) and examines their Bundle-NativeCode using the class NativeCodeFinder. If one has troubles, try to add breakpoints at the relevant functions. getNativePath() returns the entries as read by the OSGIpart.
I have a Spring framework based Java web application, which has been built in SpringSource Tool Suite ("STS"), and a local copy of Apache Tomcat. We also have a internal production server, again running Tomcat.
When I run the application on my development machine, and carry out a specific action in the web application, everything works correctly. However, when I deploy the web application to Tomcat on the server (via a war file produced by maven), and repeat those aforementioned specific actions, I'm presented with some unexpected behaviour. When I checked the server tomcat log file, I found this...
2011-11-16 19:36:45,090 [http-8280-Processor1] ERROR [attachments] invoke - Servlet.service() for servlet attachments threw exception java.lang.NoSuchMethodError: net.wmfs.coalesce.aa.dao.MediaDao.updateAlfrescoNodeRef(Ljava/lang/Long;Ljava/lang/String;)V
at net.wmfs.coalesce.aa.service.impl.MediaServiceImpl.doFileUpload(MediaServiceImpl.java:102)
at net.wmfs.coalesce.aa.servlet.MediaServlet.doFileUpload(MediaServlet.java:83)
at net.wmfs.coalesce.aa.servlet.MediaServlet.doPost(MediaServlet.java:55)
Now, the updateAlfrescoNodeRef method definitly exists in the MediaDao class - otherwise my code would not compile in STS...
package net.wmfs.coalesce.aa.dao;
public class MediaDao extends JdbcDaoSupport {
public void updateAlfrescoNodeRef(final Long recordId, final String nodeRef) {
// java code
}
}
As you can see, the method signature is correct.
I suspected that there may have been a problem when maven produced the war file, so I extracted the war files contents. In the WEB-INF/lib folder, I found the jar file which holds the MediaDao class, and extracted its contents. I then did a...
cat ./MediaDao.class
Now, as class files are binary files, I mostly saw gobledegook. However, I was able to clearly make out references to the updateAlfrescoNodeRef method, as well as the contents of a String in that method. So, this means that the method is definitely there.
The bean configuration in the Spring framework XML files is definitely correct, or the code would not run when I execute it on my development machine.
Googling suggested a library conflict on the server, but all the referenced classes - MediaServlet, MediaServiceImpl, MediaDao - are in the main project (the one with the WEB-INF folder in it). While its conceivable there may be multiple copies of the dependencies on the server, there is definitely only one copy of the main project jar.
Does anyone have any ideas why this is happening?
The problem has now been resolved. Thank you everyone for your assistance.
It turns out that the main project had a dependency which had another MediaDao class, in exactly the same package path. Someone had basically copied the class into that dependency (as a library resource so that lots of projects could use it without specifying the main project as a dependency). However, that someone had not removed the class in the main project.
So, when I modified the class in the main project (I added the updateAlfrescoNodeRef method), and ran the application in STS on my machine, Tomcat used the version of the class in the main project, and not in the library because the library project was closed. When the application was deployed to the server however, it looks like the version of the class in the library was used instead (which, of course, didn't have the updateAlfrescoNodeRef method in it).
Expert tip if you ever find yourself in a similar situation: In STS, press CTRL+SHIFT+T to open the "Open Type" dialog, and enter the name of the problematic class to see a list of projects that have a class with that name.
If the error occured in android studio, it also can be a bug of the Instant Run. In that case: File -> Invalidate Caches/Restart. It solved my problem
If you are using Tomcat 6+, look in ~tomcat/lib for conflicting classes and jars.
In Tomcat 5, look in ~tomcat/common/classes, ~tomcat/common/lib, ~tomcat/shared/classes and ~tomcat/shared/lib.