A have jar B in build path,
B have jar C in build path,
Can I use classes in C in A ?
Thanks in advance
If you have A, B and C in your class path you can use any of these classes from any other class. All you need is a reference or a reference to a reference etc.
I think you may need to distinguish between building these jars and the subsequent usage.
e.g. you can build jar B referencing jar C, but the two would need to be deployed together. If you don't then in your build for jar A, you reference jar B, but it wouldn't work without jar C.
Your build could alternatively take the code for B, and package it together with the contents of jar C. Then you could use B and C together in A.
This dependency management can become quite complex (as you can see). Packaging code together such that you don't have to provide multiple jars makes life easy (you only reference one jar), but it makes upgrades a pain (you can't upgrade, say, one common lib). Tools like Maven provide options for dealing with this (do I need this jar for compilation only, do I package it with my program, is it used for testing only etc.)
having jar b and jar c in build path is not enough.
You can use any of these options to achieve what you want:
add a new line in jar b manifest containing
Class-Path: c.jar
add a new line to jar a manifest containing
Class-Path: b.jar
java -cp a.jar;b.jar;c.jar yourfullclassname
Related
I'm currently wondering if you can compile Java class files without their dependencies, like .o files in C or C++. For example, I have a class A that has an instance of class B inside, but I only want to compile class A. Is there a way to do it? The point is to compile a java program using make because Gradle and Maven just won't let me do what I want to do.
Thank you.
Java is a statically typed language, like C/C++, so any class or method used by your class must be well-known, in order to compile your class.
In C/C++, we use header files to define classes and methods, without implementing them. That way we can compile classes that use them, using only the headers files, not the source files of the required classes/methods.
Java doesn't have header files, so the classes/methods must be available in full. They don't have to be available as source code, i.e. they can be pre-compiled and made available as .class files, most often packaged in .jar files.
So if you have class A depending on class B, you can compile B separately, then compile A separately, as long as B.class is on the classpath.
Unlike C/C++, the Java compiler can compile many files together, which is e.g. needed if A and B depends on each other (circular dependency).
If A and B are part of the same project, then compile them together. If A and B are part of different projects, build project B first, resulting in a B.jar file, then build project A, and give the jar file on the classpath when building project A.
It worth to mention that I am using maven as my build management tool. I have a jar (let's call it dep.jar) which will be included into the final project (final.jar) as dependency.
dep.jar has a class with main method.
I need to have several entry points (classes with main methods) within my final.jar's top level directory so I can use entry point depending on my need. Including one from dep.jar.
I considered:
Changing META-INF/MANIFEST.MF file within jar. As Oracle stated that is not possible to reference main classes inside jar's dependencies (BOOT-INF/lib directory) -> https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html;
Uber jar - not an option, I am dependent on jar directory structure inside Java code base
Using special class loader like this one http://www.jdotsoft.com/JarClassLoader.php. But it implies changing final.jar's main method which I cannot do due to project restrictions.
Using maven-dependency-plugin but it can unpack inner jar (dep.jar) and copy classes to maven working directory target which during packaging phase will be packed to BOOT-INF/classes directory. Again, I cannot reference main classes from there. If I unpack and copy them somewhere different than target - copied classes will not appear in my final.jar
Is there any other plugin or option how to add classes from final.jar dependant jar dep.jar during JAR build to final.jar's top level?
EDIT:
final.jar project looks like this:
final.jar
|_______BOOT-INF
|_______lib
| |_______dep.jar (contains main class I want to invoke)
|_______classes
|__________dir (directory I want to copy on demand with help of CLI)
I found a solution here Spring Boot - How to specify an alternate start-class? (Multiple Entry Points). Ended up using -Dloader.main property when launching jar.
Command line looks like these: java -jar -Dloader.main=<main_class> ./final.jar
So I have 2 projects A and B, A having a dependency on B in pom.xml . I have a file in A which wants to use a resource in B called C.wsdl. I use the following way to refer it:
wsdlLocation="classpath:/wsdl/C/C.wsdl"
I installed B then installed A using maven. I open A's target folder and find A.zip. I extract A.zip and find a lib folder containing B's jar file. I extract the jar which has a folder C containing C.wsdl.
But I get the following error
Can't find wsdl at classpath:/wsdl/QuerySubscriberInfoService/QuerySubscriberInfoService?wsdl
Also that works if the file is in A itself.
Any idea where Im going wrong with this?
Seemingly, the author of this topic is having similiar problems, please check
XSD and WSDL in different directories
If this is possible for you to initialize wsdlLocation dynamically,
you can use
ClassLoader.getSystemResource("wsdl/C/C.wsdl")
Please note that it is only possible to extract content of such files (which are packaged inside of dependant jar) only via streams, i.e
ClassLoader.getSystemResourceAsStream("wsdl/C/C.wsdl")
I have a project name: examplePrj.
This projects contains 3 jar (which includes in the build path of examplePrj)
the 3 jars are: A.jar, B.jar, C.jar
Let say that A.jar and B.jar contains tbd.jar.
And we said that examplePrj contains A.jar and B.jar
Does tbd.jar will be included twise ?
Is there any influence on the performance ?
Same as Q1, but in addition the project examplePrj contains the tbd.jar (total 3 includes)
?
First thing to note here is that classes inside the JARs are loaded by the classloader.
Now considering that tbd.jar has same classes inside it, Oracle will load these classes only once. The order in which you specify multiple class path entries is important. The Java interpreter will look for classes in the directories in the order they appear in the class path variable.
I'm having troubles compiling a mixture of clojure and java files into a single package. The files have dependencies between each other and if they were all just java files the java compiler could handle all of this. Just to make this concrete I want to create a package called pkg with 4 files, A.java, b.clj, c.clj, and D.java. A.java contains main and creates an object declared in b.clj, b.clj calls functions in c.clj and uses objects of class D. How do I write the project file?
If I use
:prep-tasks ["javac" "compile"]
in the project file then I get a complaint while compiling A.java that something in pkg.b or pkg.c is undefined. If I use
:prep-tasks ["compile" "javac"]
I get a complaint that class pkg.D does not exist. If I try
:prep-tasks [["javac" "pkg/D.java"] "compile" "javac"]
it can't find pkg/D.java, even though I set java-source-paths correctly.
One way to handle this would be to create 3 packages, one that contains A.java, one that contains b.clj and c.clj, and one that contains D.java. Then build a jar for D.java, a jar for b and c, that uses D.jar, and a jar for A that uses bc.jar and D.jar. Ugly, though.
You cannot have circular dependencies between the java and clojure sources in a single lein project. As you correctly point out, you could split the project in more than one package to avoid the circular dependency, but you don't need 3 packages but just 2, as lein supports Clojure -> Java dependencies. So you could have a project with b, c and D and another one with just A.
Another option would be just to write A in Clojure so you avoid the burden of multiple projects.