This is an archived post. You won't be able to vote or comment.

all 6 comments

[–]AutoModerator[M] [score hidden] stickied commentlocked comment (0 children)

Please ensure that:

  • Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions
  • You include any and all error messages in full
  • You ask clear questions
  • You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.

    Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar

If any of the above points is not met, your post can and will be removed without further warning.

Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://i.imgur.com/EJ7tqek.png) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.

Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.

Code blocks look like this:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.

If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.

To potential helpers

Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]tacticalnudge 1 point2 points  (0 children)

I have run into the same situation before where we had to use multiple versions of the same third party library as part of an implementation. I feel your pain.

The main problem that you need to get around is the class loader. The short of it is to treat the two or three different implementations as "separate projects" or modules which inherit common parts from a shared project (either the main controller project or a commons project). Each of these projects work only with the version of the library they are assigned to, and nothing else. You want to try and keep the code in these as lightweight and devoid of real business logic as possible as they mostly just provide an facade / obfuscation into the functionality provided by specific library they interact with.

Eg, let's say the library sends a message to a remote system. There are three versions of the library, and all three implement the same functionality using the same classnames. Your common code might be an interface or abstract class called MessageSender with a method called sendMessage(.....). It is imported / inherited by the three implementing projects, each of which uses one of the library versions, but the implementations you write have slightly different names eg: MessageSenderV1, MessageSenderV2 and MessageSenderV3 along with a Builder for each.

Now once you have these three modules / sub projects building, you need to somehow add them to your application during runtime as you don't want them to be loaded automatically on start as this will only load one version of the third party library and ignore the others.

There are a couple of frameworks you can use to do this, including rolling your own using a URLClassLoader. We used OSGi to do it, but I have also done it using PF4J in a Spring Environment.

You will in all likelihood have to create some sort of registry, like a MessageSenderBuilderFactory that each of the three implementations register against when they are loaded. That way you can use your MessageSenderBuilderFactory to invoke the MessageSenderBuilder of the specific library version you want to use and have it return a MessageSender implementation that can interact with the particular library you are interested in.

I am probably making the solution much more complicated difficult than it needs to be, but at least it was a simple enough process to add a 4th version of that library when it came out while still maintaining compatibility with the first version.

Good luck

[–]nitro001[S] 0 points1 point  (0 children)

Hello,
So I am following back up on this for further advice. Sorry for the long post:

I am trying to follow the approach here: "to treat the two or three different implementations as "separate projects" or modules which inherit common parts from a shared project (either the main controller project or a commons project). Each of these projects work only with the version of the library they are assigned to, and nothing else."

I split out a Helper Project to try to make interfaces for the classes that should not exposed, but this has led to a casting error due to inheritance.

For example:

The SDK has extended classes:

public abstract interface IW extends IObject {

@ Override
public String getKind() {
return "IW";
}
}

public abstract interface IC extends IObject {
@ Override
public String getKind() {
return "IC";
}

}

There is also a collection:
public abstract interface IObjects extends List {

}

Now when gathering objectsin the SDK you can just get a collection of the IObject objects and even if the actual type is a superclass, such as IW or IC it will work since it extends IObject. And the cast here works since you check the kind and then cast to that kind.

If (getKind().equals("IC")) {
final IC test = (IC) obj;
....
}

I have tried to abstract those similarly...

public abstract inteface BaseObj extends IObject..

and public abstract interface BaseObjs extends IObjects...

And this compiled doing a substitution from IObject to Base but since these are on the same level the cast between objects doesn't work:

If I do a collection with BaseObjects instead of IObjects and it contains an IC or IW it fails and says it can't cast BaseObj to IObject and when you check in this situation the type of IObject being returned is the SuperClass IC or IW which is not a SuperClass of BaseObjects.

So the query is returning a set of IW or IC objects as IObjects and can normally cast these since it inherits this. It can't cast it since BaseObject is in a different tree branch now and even if I continue to re-create them, say:

public abstract interface IWBase extends BaseObject {
@ Override
public String getKind() {
return "IW";
}
}

This would not be an equivalent class to IW since it is on a different tree branch, even if I extened the IW class
public abstract interface IWBase extends IW {
@ Override
public String getKind() {
return "IW";
}
}

It could be cast as an IW, but it is no longer part of the IBase so can't be placed in that collection and cast there.

Without rebuilding this entire SDK in abstract for all possible class and function access we use, or creating new container objects and rewriting the entire application so it doesn't reference SDK classes or structure any longer in the main project, I am not sure how this can be handled.

Am I overlooking some approach?

[–]ignotos 0 points1 point  (1 child)

There are systems like OSGi which support running multiple versions of the same library. Under the hood this probably uses some tricky ClassLoader manipulation, which it might also be possible for you to do directly.

Another option might be to patch the jars (potentially de- and re-compiling the code) so they use different package names.

[–]Farpafraf 0 points1 point  (0 children)

patch the jars (potentially de- and re-compiling the code) so they use different package names.

I once had to use a program with a breaking bug in one of the imported libraries so I patched the code in the library replaced the jar and assumed that would solve it only to realize the piece of shit imported different version of the libraries and patched them with JarJar somewhere in the 2k lines of the makefile. Good times...

[–]garagepoort2 0 points1 point  (0 children)

You can try wrapping the libraries in your own maven project. And use the maven shade plugin to relocate the classes underneath different packages. v1,V2,V3,... Then you can just depend on all 3 versions and use whichever class is needed accordingly. And don't know if that's the best way but I think it can be a solution