In my maven project, there were two different jars but contain the same class with the same package name. Can that cause NoSuchMethodError?
I know if the method does't exist will cause this Error? What if there have the method, but duplicate?
This usually happens when you have two versions of the same project on the classpath and they changed the API. Depending on which JAR is looked at first, the method will be found or not.
If the method exists in both JARs, then it will work but something else might fail (there will be other differences).
If you add the same JAR several times on the classpath, then it will always work.
Solutions:
Always make sure the classpath is clean. Every fully qualified class name should resolve to a single class resource (file).
Sometimes, people add classes from different projects to their JARs "to make them easier to use." If that is the case, then open the JAR with a ZIP tool and delete the extra classes. Maven works better without such "help".
If the conflict exists, and the method exists in both classes, the error won't show, however its a common case that there's a difference in a signature, between the conflicting versions, which can confuse you. My advice, check if the signature of the loaded class matches, and work your exclusions properly
Related
I am trying to use the Aspectj compiler ajc in a modular (OSGi setting). The standard way ajc seems to be used is to take aspects & java code and turn it into one a JAR with all classes and resources in the -inpath, -aspectpath, and -sourceroots.
I am trying to weave aspects an OSGi executable JAR from bnd. This executable jar contains a set of bundles that need to be woven. However, in a modular system, the boundary is quite important. For one, the manifest often contains highly relevant information to that bundle or one of the many extenders. Flattening all the classes into a big blog won't work.
I am therefore weaving each bundle separately. However, then the output is cluttered with the aspects. I'd like to import these to keep the aspect modules proper modules. However, using the annotation programming model, I notice that ajc is modifying the aspect modules, so I need to rewrite those as well. This is fine, but since I weave each bundle separately, I have the question if the weaving of the aspect could depend on what gets other modules woven? That is,
does the modification of the annotated aspect depend on the classes that it is woven in?
The other issue is what happens to resources with the same name? Since my -inpath is only one JAR (the bundle), I notice I end up with the correct manifest (META-INF/MANIFEST.MF) in the output. However, if the -inpath consists of many bundles, what will the manifest be? Or any other resource that has the same path and thus overlaps?
Last issue is external dependencies. I understand acj wants to see the whole world and include this whole world into the output JAR. However, I must exclude external dependencies of a bundle. Is there a way to mark JARs as: use, but do not include. A bit like the maven 'provided' scope?
Summary:
Does the modification of an #Aspect annotated class depend on the targets that is applied to?
Can I compile the #Aspect annotated classes into separate JARs?
How to handle the external dependencies that will be provided in the runtime and thus must be excluded from the output JAR.
What are the rules around overlapping resource paths in the -inpath and -sourceroots?
UPDATE In the mean time I've made an implementation in Bndtools.
Does the modification of an #Aspect annotated class depend on the targets that is applied to?
If you want to be 100% sure you have to read the AspectJ source code, but I would assume that an aspect's byte code is independent of its target classes, because otherwise you could not compile aspects separately and also not build aspect libraries.
Can I compile the #Aspect annotated classes into separate JARs?
Absolutely, see above.
How to handle the external dependencies that will be provided in the runtime and thus must be excluded from the output JAR.
If I understand the question correctly, you probably want to put them on the class path during compilation, not on the inpath.
What are the rules around overlapping resource paths in the -inpath and -sourceroots?
Again, probably you have to look at the source code. If I was you I would simply assume that the selection order is undefined and make sure to not have duplicates in the first place. There should be Maven plugins helping you with filtering the way you want the result to be.
bndtools seems to have close ties to Eclipse. So does AspectJ as an Eclipse project. Maybe you can connect with Andy Clement, the AspectJ maintainer. He is so swamped with his day-time job though, he hardly ever has any free cycles. I am trying to unburden him as much as I can, but OSGi is one of my blind spots and I hardly know the AspectJ source code. I am rather an advanced user.
I need to read properties file located inside resources folder of buildSrc special module to create kotlin object which will be accessible by other project modules.
I tried to put this properties file
in the root project folder(this case sometimes works sometimes not, so I look for more reliable case)
inside of buildSrc folder directly
and now trying by putting inside "conventional" resources folder inside buildSrc which even highlighted by ide as recognized resources folder
But during assembling of modules I get Exception file not found on the line load()
So 2 questions:
where properties file should be located
how to read it from kotlin inside buildSrc module.
Gradle has a somewhat complex class-loading hierarchy, and I don't know enough of it to be able to explain what is going on under the hood. However, I can give you some hints.
First of all, the methods getResource and getResourceAsStream is present in both a Class and a ClassLoader, and they behave differently.
On a Class, if you don't prefix it with a slash, it will look for resources relative to the package of the class. With a slash, it looks at the root of the hierarchy. As you don't know the package of the compiled script as done by Gradle, the correct way to reference the file is javaClass.getResourceAsStream("/file.properties") (notice the slash).
If you use the methods from a ClassLoader instead, a leading slash is meaningless. So here, Thread.currentThread().contextClassLoader.getResource("file.properties")) is correct.
The last thing to consider is when you can use the methods from the class and when you have to use a ClassLoader. From what I can tell, you can use the class method when in the same project (or plugin). So this should work from within buildSrc. But if you want to get the resource outside buildSrc, I believe you need to go through the context classloader.
After trying different variants I have found 100% stable and working variant - instead of reading a properties file, parsing it and validating input - just use kotlin objects as ready to use configuration! With this approach the problem of a current folder and accessibility of resources is gone which is what I needed.
I have a problem understanding the internal access modifier. In my examples I could not produce any situation where it behaves different then public. Even if I create a jars I can access the internal functions in the jar from outside the jar (from a different package unrelated to the one used in the jar). In the documentation the term module is used but I could not find out what a module is exactly.
My questions thus are:
what is a module in kotlin?
how does the access modifier internal differs from the public modiefier?
The Kotlin compiler version M8 (0.8.11) ignores modules, more precisely, it works as if all your code were put into the same module, this is why you can't get a visibility error for internal.
Starting with the next milestone release, every IDE module you create has its own visibility scope, and when you try to access an internal declaration from one module in another, you get an error. Publics, on the other hand, are visible across the whole project.
UPDATE: This has not been turned on in M8, postponed for later
UPDATE: This has been turned on since later Kotlin milestones and betas
I have a project with more than an hundred external library dependencies, here we use tomcat with this endorsed jar libs configured on a directory in the server (now is under $CATALINA_HOME/lib/endorsed), so the webapp can access those resources on runtime start.
I wanted to try jetty instead, because tomcat takes too much memory and crashes frequently. Now I'm wondering if there is a parameter to pass on maven-jetty-plugin to specify this jar's folder so as the webapp class loader find them in its classpath.
I've tried extraClasspath in configuration tag, but it seems to load only classes and ignore all jars in the directory I set into (if I pass the full name path of the jar, it is loaded, but I don't want to set every library that I need there).
Thanks in advance for the help
update:I know it's not a standard maven operation, i'm searching for an emergency workaround since this project is very huge and I can't refactor as I want.
But also I expected this feature was not as tricky as it seemed to me at first glance.
You need to pass them as absolute paths, or, alternatively, have them as dependencies of the plugin itself.
What you want to have done goes against Maven's portability principles, so don't expect it to support it.
I've got an interesting question about classloader behavior.
Question one: What is the order in which the classloader will load jars?
The following jars and containing classes are given:
a.jar
+-com/scheffield/foo/A.class
b.jar
+-com/scheffield/foo/B.class
Which class will be loaded?
Question two: Is it true that the path and name of a file in the classpath is unique?
The following jars and containing classes are given (realworld example):
spring-beans-3.0.3.RELEASE.jar
+-META-INF/spring.schemas
spring-aop-3.0.3.RELEASE.jar
+-META-INF/spring.schemas
What I can tell you is that both files are be loaded by Spring otherwise an exception would occur (see this article).
Why am I asking that:
I made a so called big jar (cookbook entry for gradle). Thats a jar with the application classes and all other dependencies unzipped and packet in the big jar. And I'm not absolutely sure what to do with duplicated files.
Classes are resolved however a classloader wants to resolve them (that's the whole point of having a classloader architecture). Most classloaders you deal with in practice are variants of java.net.URLClassLoader which loads classes (and resources) based on a search path (class path) of directories and jars. Each location in the search path is treated as a source of classes and the locations are searched in order.
No, names are not unique. The first one encountered in the search order will be used.
If you combine jars into one big jar there is a definite possibility of conflict. If you are careful to merge them from the last source in your effective classpath to the first (thus overriding later jars with earlier jars), you will get approximately the same result.
I say approximately because the manifests in jars contain additional processing instructions that need to be merged as well. For example, a manifest can contain a Class-Path attribute that includes additional jars in the classpath. It's possible to merge jars but lose manifest attributes that are specifying part of your actual necessary classpath. If your manifest contains sealed or signed jars then you might not be able to do this merging at all without violating the signed parts of the jar.
In summary, jars are not really designed to be merged in this way. It can work but there are many possibilities for error, some of which are not possible to solve. One common cause of error is to merge two jar files and end up with more than one entry with the same path, which is allowed in zip files. The ant jar and zip tasks allow you to merge multiple sources and can produce these kinds of issues.
Really, it's better to instead bundle web apps consisting of many jars and sources into a single WAR or EAR archive. That's kind of the whole point of why they exist.
the files are being loaded in the order the containing jars appear on the classpath. this applies to classes. if you are loading other resources (like the spring.schema) you may use either classloader.getResource(...) or classloader.getResources(...). the first one returnes the first resource on the classpath, the second one also returnes shadowed resources.
I don't think a valid zip archive contains duplicate entries.
regards