1

I have a problem in my Java project, I have a bunch of projects (for example A, B, C…) that happen to have a Tools class in a tool folder in a path such as src.tool.Tools, the same path and same class name for all of them.

Now, I have my project Z that has in its build path all of these projects (A, B, C…). How can I make sure that when I import one Tool class I am importing the one I really need?

More complicated, if in A.Tool I have a method such as public int tool(){return 1} and in B.Tool another method such as public int tool(){return 0} How can I make sure I call the function I really want?

Thanks for all!

Random
  • 1,105
  • 5
  • 24
  • 37
  • I don't think you can control with class is used. This is determined by the order of the jar files in the class path. (The first jar file that provides the class will be used.) – aioobe Jun 28 '13 at 08:07
  • You need to make sure that the package names are unique, like `a.tool`, `b.tool` etc. instead of having the same package name in each project. – Andreas Fester Jun 28 '13 at 08:08
  • 1
    It seems like a very bad design that results in methods (not functions) having ***exactly*** the same name. You should look to rename them with better names, rather than all this shenanigans. – Andrew Thompson Jun 28 '13 at 08:09
  • Thanks for all the quick responses, unfortunatly I am not in charge and have no power over the naming, but I hope that pointing to this error whould make the powers that be changed the naming, thanks! – Random Jun 28 '13 at 08:16

4 Answers4

3

Three options:

The risky way: make sure then class you really want comes first in the classpath and every classloader involved, processes them in that order. This can break extremely easy with very confusing results. You can't access multiple versions of the class, you can only control which on you get. Don't do this.

The complicated way: Create classloaders for each project you depend on and adress the specific classloader to load the class. That is a lot of work to get right, you might be able to use OSGI for this. Do this only if your main aim is to learn about class loaders.

The simple and right way: Refactor your projects so all packages in each project have the project name (or some representation of it) in the package name. This makes each package name unique and you can access classes without any problem (possibly using the full qualified class name if you have to use multiple Tool classes in one place) While you're at it, you might as well rename the Tool classes that actually describes the purpose, class and package names like "Util", "Tool" or "Misc" are really really bad code smells.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • It seems that refactoring is the simple as most elegant way to solve this problem, that it is not prone to give a lot of headaches in the future. Thanks! – Random Jun 28 '13 at 08:29
1

Probably using a user-defined class loader:

Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader. Applications employ user-defined class loaders in order to extend the manner in which the Java Virtual Machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.

1

I don't think it is possible to do what you want. If you have three classes all called "src.tool.Tools", Java doesn't care what jar file you loaded them from. If all three projects (which I am assuming means jar files) have this same class, Java will have a clash and you can't predict which Tools it is going to load.

The only way to make sure the correct one is getting called is making sure the other two are not in the classpath.

There is a hack solution to your problem. You could create a new ClassLoader for each project and ask the ClassLoader for the desired project for the Tools class. Then using reflection you can instantiate it and call the method. Since each project is in its own ClassLoader, the three Tools classes won't clash anymore.

Ex:

URLClassLoader a = new URLClassLoader(aJar.toURL(), getClass().getClassLoader());  
Class toolsClass = Class.forName("src.tool.Tools", true, a);  
Method m = toolsClass.getDeclaredMethod("tool");  
Object i = toolsClass.newInstance();  
Object result = m.invoke(instance);  

(URLClassLoader example pulled from How should I load Jars dynamically at runtime?)

Community
  • 1
  • 1
Kazar
  • 56
  • 2
  • Yes, you are right, project means jar. Sorry for the bad naming I was thinking in eclipse terms. – Random Jun 28 '13 at 08:20
0

Assuming that your projects A,B,C each have different package namespaces, e.g. com.you.A, com.you.B, etc, your Tools class will now be available in multiple locations like com.you.A.tool.Tools, com.you.B.tool.Tools, etc.

So when in project Z you create an instance of Tools class, you can specify the exact class to use while declaring the object reference variable.

private com.you.A.tool.Tools toolsFromA;
private com.you.B.tool.Tools toolsFromB;

calling toolsFromA.tool() will return 1 and calling toolsFromB.tool() will return 0.

Jit B
  • 1,206
  • 14
  • 26
  • Sorry for my bad writing I have not explained myself well enough. The problem is that they have the same package namespace. For example in Jar A I have com.you.tool.Tools and in Jar B I have com.you.tool.Tools – Random Jun 28 '13 at 08:22
  • _Assuming that your projects A,B,C each have different package namespaces_ Well, **they don't** – BackSlash Jun 28 '13 at 08:23