Maven/Java-how to specify which jar file to use - java

I have feeling I will get down voted. Please pardon my ignorance on this subject as I need to get this working soon.
Basically, I have two dependencies. Same GroupId, Same Version, but different artifactID.
There are duplicated Classes in these two artifacts, but one of them has some beta features.
How do I ensure part of my code use classes from Jar1, the rest of my code use classes from Jar2 ?
My bad. There is no overlap. Sorry for all the confusion :-(

What about creating two projects? One dependent on artifactID1 other other dependent on artifactID2. One project would then depend on the other project. This is predicated on all the code using one version of the jar not being dependent on code that uses the other version.

Related

Pulling in a subset of classes from a sibling project

In my root project, I have many sub-projects:
common
dependant-1
dependant-2
...
standalone
In this scenario, common is a shared library. All other projects are dependant on it, with the exception of standalone. (standalone is actually a standalone client JAR).
What I would like to do is get 5 classes from common into the jar file produced in standalone. I only need those exact 5 classes (out of ~200) and want to avoid bringing common as a full dependency (along with all of common's dependencies). Granted it's an unusual setup, but I don't want to include classes that the client has no business with and the classes I am including just contain enum or static final.
So far, I have tried the following in the build.gradle for standalone:
jar {
manifest.attributes(
// .... Removed
)
with project(':common').jar {
include('com/classpath/ClassA.class')
include('com/classpath/ClassB.class')
include('com/classpath/ClassC.class')
include('com/classpath/ClassD.class')
include('com/classpath/ClassE.class')
}
}
This works very well for the standalone project, but tramples the other projects that were fully dependant on common; common.jar will now only ever contain the classes listed above, regardless of which dependant project.
(I'm guessing this is expected behaviour: in Gradle's configuration phase, it sees the specific configuration I have for common in standalone and applies that to common).
So, in short, what is the neatest solution to this? I'm thinking that I may need to provide a configuration in the build.gradle for the common project. I'm not sure how to do this yet (RTFM). I just wanted to check that there isn't a better approach to this?
EDIT: to answer some of alexvetter's questions.
I hadn't yet tried to include them from build/classes, but this did the trick (see the accepted answer).
I did consider creating a new common-base project. If there were much more than 5 classes that I needed, I absolutely would have gone this way. And yes, I only need the classes at runtime.
Just to clarify the last point... the standalone jar file is actually a JAX-WS client jar that we provide to another team. The reason I needed to inlcude these specific classes in the client JAR is so that the client knows what values to give to certain web service method calls. Ideally, I would have replaced all of the included classes with enum (like I mentioned, they are literally just static final definitions) and JAX-WS would have looked after everything. (I actually did this to replace one of the class files that I was including.) If I had done this for all the classes I needed to include, it would have triggered many more code changes for them (why this was a problem is a whole different story ;)
Following should do the trick:
from("${project(':common').buildDir}/classes/main") {
include('com/classpath/ClassA.class')
include('com/classpath/ClassB.class')
include('com/classpath/ClassC.class')
include('com/classpath/ClassD.class')
include('com/classpath/ClassE.class')
}
But as I already stated in my comments. This classes are only available on runtime and you should probably create a new project (e.g. base) which is a dependency of common and standalone

Use of modules within Java programming

Hopefully this is a question that only needs a fairly quick answer, but I haven't had much luck finding something online that is in terms I understand!
Quite simply, I'm working on my first real project in Java, a text adventure, (using IntelliJ IDEA) and I was just wondering if I need to be splitting my code into modules? So, for my monsters, should I keep all of my monster classes within a module called Monsters, or can I just keep it in the same module?
I only ask because; a) I wasn't sure whether it was a done thing in order to keep the project tidy and b) When I tried to create a Monster module, I received a warning telling me that the files in this module wouldn't be accessible from the rest of the program, which seems to defeat the object to me...
Many thanks in advance for any advice!
I believe you are referring to IntelliJ's concept of a module. As stated on their page:
A module is a discrete unit of functionality which you can compile, run, test and debug
independently.
Modules contain everything that is required for their specific tasks:
source code, build scripts, unit tests, deployment descriptors, and
documentation. However, modules exist and are functional only in the
context of a project.
So, modules should not be referencing the source code from other modules. They should essentially be completely different units.
As in thecbuilder's answer, you should look into using Java's packaging system instead.
By modules if you mean packages, then its a good habit to keep related classes in one package and distributing unrelated classes in different packages.
And to the thing, that the classes wouldn't be accessible, you'll have to make them public to access them from different packages.
More on package structuring :
http://www.javapractices.com/topic/TopicAction.do?Id=205
http://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
https://stackoverflow.com/a/3226371/3603806
For access specifiers :
Taken from : http://www.go4expert.com/articles/java-access-specifiers-t28019/

Two JARs on buildpath with identical method names but different constructors. How can I specify which JAR's method to use?

I am building a tool from several different open source libraries. My buildpath is in the following order:
My first JAR file, stanford-corenlp-3.3.0.jar, contains a package called edu.stanford.nlp.process, which has the Morphology.class class.
My second JAR file, ark-tweet-nlp-0.3.2.jar, contains an identical package name (edu.stanford.nlp.process), and an identical class name Morphology.class.
In both JARS, inside their respective Morphology classes there exists a method called stem(). However, the constructors for these methods are different. I want to use the stem(String, String) method from my second JAR file, but since the import statement (import edu.stanford.nlp.process.Morphology;) does not specify which JAR to use, I get an error since it thinks the first JAR on the buildpath is the one I want to implement.
I don't want to change the order of my buildpath since it would throw off my other method calls.
How can I specify which JAR's Morphology class to use? Is there an import statement that specifies the JAR, along with the package.class?
EDIT: What about a way to combine my two JARs so that the two Morphology classes merge, giving me two methods with different constructors?
As several others pointed out above, it is possible to tweak Java's classloader mechanism to load classes from certain places… but this is not what you are looking for, believe me.
You hit a known problem. Instead of worrying how to tell Java to use a class from one JAR and not from the other, you should consider using a different version of ArkTweet.
Fetch the ArkTweet JAR from Maven Central. It does not contain Stanford classes.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
The default ClassLoader will only load one of the jars, ignoring the second one, so this can't be done out of the box. Maybe a custom ClassLoader can help.
For more info about ClassLoaders start from here.
Good luck!
EDIT: We are looking at some horrible packaging choices causing as side effect this Jar Hell here. The author of this "Ark Twitter" library decided it was a good idea to release a JAR artifact that includes a third party library (the Stanford NLP library). This leads to unnecessarily tight coupling between Ark Twitter and the specific version of the Stanford NLP library used by it. This is a very bad practice that should be discouraged in any case: this violates the whole idea about transitive dependencies.
EDIT (continued): One possible (and hopefully working) solution is to rebuild the Ark Twitter JAR so that it does not include the aforementioned library but only its own code (basically the cmu.arktweetnlp package only) and hoping that the version of NLP required by your project works with Ark Twitter. Ideally you should submit a pull request to the author of the library but in the meantime you can get away with un-jarring and re-jarring the existing JAR file.
EDIT 2: Looking at the JAR file again, it's much worse that I originally thought: ALL the dependencies are repackaged in the released JAR file. This is really the worst possible solution for releasing a library. Good luck.
I think your problem can be solved simply by using the lemma(String word, String tag) method in the current CoreNLP's Morphology class:
String word = ...;
String tag = ...;
String lemma = morphology.lemma(word, tag);
WordTag wt = new WordTag(lemma, tag);
When the class was revised a couple of years ago, the method you're looking for was deleted. The feeling was that with most of the Stanford NLP code moving to using CoreLabels, methods that return WordTag are less useful (though deleting all such methods is still a work in progress).
No there isn't. This is a weakness of Java, that cannot be simply solved. You should use only one of the libraries. Having both on the classpath will make java always select the first one.
This problem is named as Jar hell.
The order in the buildpath generally determines the order in which the classloader will search for the class. In general, though, you don't want duplicates of the same class in your build path--and it sure doesn't seem like ark-tweet-nlp-0.3.2.jar should have a edu.stanford package within it.
When you load a class, it's loaded at given address, and that address is then placed in the header of objects created from the class, so that (among other things) the methods in the class can be located.
So if you somehow load ClassA, with method abc(String), from zip file XYZ.zip, that loads into address 12345. Then (using a class loader trick) you load another ClassA, with method abc(String, String), from zip file ZYX.zip, and that loads into address 67890.
Now create an instance of the first ClassA. In its header will the class address 12345. If you could somehow attempt to invoke the method abc(String,String) on that class, that method would not be found in the class at 12345. (In actuality, you will not even be able to attempt the call, since the verifier will stop you because, to it, the two classes are entirely different and you're trying to use one where the other is called for, just as if their names were entirely different.)

Java: How to share common application / UI code among several applications

I have several applications that differ mostly based on resources. As of now, I'm copying the code around to each application. This can be problematic. An example, fixing a bug in one, and forgetting to update to the others.
I don't think creating a JAR is appropriate for this situation, as these are application specific UI classes, (actually android activity classes in specific) including the actual app start-up code.
It may be possible to include these source files into several packages, but then I have the problem that each file specifies a specific package name on the first line.
Most of the code is related to the UI and Activity processing. (The actual common code is already in a library). A similar question is posted here.
Are there any elegant solutions to this situation?
A jar is absolutely appropriate for this situation. You should split your application into layers, separating the application-specific classes from the shared code.
I solved this by going with Android Library projects. (Not sure of the details, perhaps they are ultimately jars) Check out details here, specifically the section 'Setting up a Library Project'.
I basically put in all my activity classes (except for the start-up one) into the library.
For true non-UI bound code, JARs, do seem to be the way to go.
I agree with artbristol.
I also recommend to use Maven and:
release the common jars to a corporate Maven repository
declare a dependency with specific versions on these jar artifacts
Like this you don't break applications if you do some incompatible changes.

Runnable JAR with duplicate dependencies

I am trying to create a runnable JAR using Eclipse, but an running into problems. The Eclipse workspace contains two separate projects which depend on the same library. I can create the runnable JAR, but the problem is when I run it I receive a java.lang.NoSuchMethodError exception.
I believe I'm receiving the java.lang.NoSuchMethodError exception because the libraries are different versions. Is there a common solution to fix this problem? If not, what would you recommend I do?
If the major version number changes it means that backwards compatibility may have changed.
You could try with the latest version and hope that they just did add methods and that the old way of working, but even if NoSuchMethod exception is not thrown there is no guarantee (maybe with the new API you should call differente methods to get the same results).
I would contact the provider of the library and ask them if compatibility is broken. If they do not answer or it is broken, and you have the source code, the only possibility would be refactoring one of the libraries (probably 1.0); v.g. putting all of it in new packet v1. Then you would have to change the project that depends of it.
If none of the above works, then the solution would be an OSGi container or to setup project A and project B as two different executables and setup project B as a server that answer project A messages. Messy
The fix is to only include one version of the library which can satisfy both of the libraries that use it. If that's not possible, you'll have to find a different way of going about things such that you can eliminate the conflict. Options include:
Remove one or more of the uses from your code that are causing the NoSuchMethodError.
Modify the source of one or more of the libraries so they can happily coexist.
Use an OSGi container, which would allow you to have two versions of the same library in the same application.
As SJuan stated, you could use OSGI to set it up correctly. http://en.wikipedia.org/wiki/Java_Classloader#JAR_hell

Categories

Resources