I am trying decouple a third party library's abstract class. I want to expose a new abstract class which will be exposed to the users rather than the library provided class.
I initially tried using an adapter but that stills add the import for the third party lib in the adapter class.
I added code below explaining my new approach.
// third party lib
abstract class ThirdParty<S> {
public abstract S doAction(S s);
}
// my goal here is to expose a different abstract class which is decoupled from third party lib
// exposed to other modules, rather than exposing the third party lib
abstract class ExposedAbstractClass<S> {
public abstract S doAction(S source);
// get hold of type using guava lib
private final TypeToken<S> typeToken = new TypeToken<S>(getClass()) { };
public Class<S> getSourceClass() { return (Class<S>) typeToken.getClass()
}
// internal class
class Builder<S> extends ThirdPartyLib<S> {
ExposedAbstractClass exposed;
public Builder(ExposedAbstractClass exposed) {
this.exposed = exposed;
}
#Override
public S doAction(S s) {
return (S) exposed.doAction(s);
}
}
//my approach breaks here when i try to invoke builder
class InvokeThirdParty {
public void invoke (ExposedAbstractClass exposed) {
Class type = exposed.getSourceClass();
Builder<type> builder = new Builder(exposed); //doesn't work since Class is runtime type, and T is compile time type
}
}
Any guidance in terms of which design pattern to follow here would be very helpful.
I agree with GuaravJ answer, you could isolate the third party dependency and use an Adaptor or Bridge pattern to invoke the third party library from there. I believe this would be an adequate decoupled solution.
However, it would seem your intent is to remove the import, hence the dependency?
As an alternative, how about implementing Reflection on the ThirdParty class?
Java is compatible with Reflection-oriented-programming. This lets you inspect and examine classes and invoke their methods dynamically at runtime. It would eliminate the dependency and the import statement for the ThirdParty class.
In general terms, with Reflection, you have to locate the class and inspect its methods. In this case I'm assuming knowledge of the doAction() method from ThirdPartyClass.
A simple Java reflection example following the idea of your code excerpt:
Not using reflection
// import ThirdPartyLibrary statement somewhere here
// Instantiating object with concrete class that implements methods from ThirdParty. From your code now, it would be "Builder".
ThirdParty<S> thirdPartyObject = new ThirdPartyImp<S>();
// Invoking doAction method which returns an S object
S foo = thirdPartyObject.doAction();
Using reflection
// Inspect the class finding it using its path and instantiating an object
ThirdParty<S> thirdPartyObject = Class.forName("classpath.to.ThirdPartyImp").newInstance(); // Using a concrete class to instantiate.
// Finding the doAction method. This is assuming we have knowledge that a method with this name exists. Reflection could go as deep as not knowing the methods and having some control structure inspecting them.
Method doAction = thirdPartyObject.getClass().getDeclaredMethod("doAction", new Class<?>[0]);
// Do action is invoked and it returns an object S.
S foo = thirdPartyObject.invoke(thirdPartyObject);
Further reading and notes
Oracle Java official documentation on reflection
Java Reflection example tutorial
Wikipedia Reflection (Computer Science) definition and examples
Related
I need to support two versions of a dependency, which have the same API but different package names.
How do I handle this without maintaining two versions of my code, with the only change being the import statement?
For local variables, I guess I could use reflection (ugly!), but I use the classes in question as method argument. If I don't want to pass around Object instances, what else can I do to abstract from the package name?
Is it maybe possible to apply a self-made interface - which is compatible to the API - to existing instances and pass them around as instance of this interface?
I am mostly actually using xtend for my code, if that changes the answer.
Since you're using Xtend, here's a solution that makes use of Xtend's #Delegate annotation. There might be better solutions that aren't based on Xtend though and this will only work for simple APIs that only consist of interfaces with exactly the same method signatures.
So assuming you have interfaces with exactly the same method signatures in different packages, e.g. like this:
package vendor.api1
interface Greeter {
def void sayHello(String name)
}
package vendor.api2
interface Greeter {
def void sayHello(String name)
}
Then you can combine both into a single interface and only use only this combined interface in your code.
package example.api
interface Greeter extends vendor.api1.Greeter, vendor.api2.Greeter {
}
This is also possible in Java so far but you would have to write a lot boilerplate for each interface method to make it work. In Xtend you can use #Delegate instead to automatically generate everything without having to care how many methods the interface has or what they look like:
package example.internal
import example.api.Greeter
import org.eclipse.xtend.lib.annotations.Delegate
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
#FinalFieldsConstructor
class GreeterImpl implements Greeter {
#Delegate val Api delegate
}
#FinalFieldsConstructor
class Greeter1Wrapper implements Greeter {
#Delegate val vendor.api1.Greeter delegate
}
#FinalFieldsConstructor
class Greeter2Wrapper implements Greeter {
#Delegate val vendor.api2.Greeter delegate
}
Both Greeter1Wrapper and Greeter2Wrapper actually implement the interface of both packages here but since the signature is identical all methods are forwarded to the respective delegate instance. These wrappers are necessary because the delegate of GreeterImpl needs to implement the same interface as GreeterImpl (usually a single delegate would be enough if the packages were the same).
Now you can decide at run-time which version to use.
val vendor.api1.Greeter greeterApi1 = ... // get from vendor API
val vendor.api2.Greeter greeterApi2 = ... // get from vendor API
val apiWrapper = switch version {
case 1: new Greeter1Wrapper(greeterApi1)
case 2: new Greeter2Wrapper(greeterApi2)
}
val example.api.Greeter myGreeter = new GreeterImpl(apiWrapper)
myGreeter.sayHello("world")
This pattern can be repeated for all interfaces. You might be able to avoid even more boilerplate by implementing a custom active annotation processor that generates all of the required classes from a single annotation.
I have an interface defined as follows:
public interface Cache {
}
Then an abstract class implementing the above:
public abstract class AbstractCache implements Cache {
}
Then a concrete class inheriting from above:
public class RealTimeCache extends AbstractCache {
}
Then another class defined as follows:
public class CacheProbe {
public static <T> T probe(T base) {
return (T) Proxy.newProxyInstance(
base.getClass().getClassLoader(),
new Class[]{Cache.class},
new MethodCountInvocationHandler(base) // I am not mentioning this class as it's irrelevant
);
}
}
I have a class as follows which is using all of the above:
public class CacheLoader<T extends Cache> {
public T load() {
T result = getResult(...);
CacheProbe x = new CacheProbe(result);
return x.probe();
}
}
Lastly, the lines causing the issue (located outside above classes):
final CacheLoader<RealTimeCache> cacheLoader = getNewLoader(); //Method of this method is irrelevant and unchangeable
RealTimeCache x = cacheLoader.load(); //This is the line which is causing a runtime issue
Problem is, at run time the following exception is thrown at the last line mentioned above:
java.lang.ClassCastException: com.sun.proxy.$Proxy57 cannot be cast to RealTimeCache
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
How do I fix this ?
Please note that I can only change CacheProbe class in order to fix this. Cache, AbstractCache, RealTimeCache, CacheLoader and those last two lines are unchangeable.
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
Yes, the docs for java.lang.reflect.Proxy say
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
(emphasis added)
Thus, you cannot use Proxy to create (an instance of) a subclass of an arbitrary class of your choice.
How do I fix this ?
You can create an ordinary subclass of RealTimeCache, and return an instance of that. Proxy is meant primarily to serve for interfaces that are not known until runtime, and in that case the only way to interact with them anyway is the interface type. That's not your scenario.
If necessary, you can implement such a subclass in terms of a MethodCountInvocationHandler, just as your proxy class uses, but I'm sure it would be easier to implement whatever tooling that is supposed to provide directly.
i have two independent projects Basic and Extension with following setup
Project A:
class Handler {
public void handle(){
...
}
}
Project B
import Handler; //from Proejct A
class SomeClass{
someMethod() {
handle(); //dependency to Project As class with handle method
}
}
So the problem is the dependecy to the handle method which exists at Project A but not at compile time on Project B.
The final step is to have build Project Extension as a jar and import it inside Project Basic.
Ofc the compiler will give me error when i build Project B since the handle is not known at compile time.
For this issue i need a solution:
Either: Tell java that the missing code (import class with handle method) will be there at running time.
Or maybe Dependency Injection due to a factory pattern.
I am known to the factory pattern, but i don't understand how it could help me in this situation.
Or another solution.
Can you help me?
Neither of these are valid Java - won't compile. The proper keyword is "class", not "Class".
You have to provide it at compile time once you get it right - you have no choice. No way around it.
Maybe you should look at the Java JDK and follow the example in the java.sql package: Interfaces. Connection, ResultSet, Statement, etc. are all interfaces so vendors can provide their own implementations. Users only deal with interfaces.
Your GenericHandler should be an interface that you provide to clients. They add their implementations and add their JAR file containing the custom implementation at runtime.
Basic interface that all extensions implement:
public interface GenericHandler {
void genericHandle();
}
Extension code:
import GenericHandler;
public class Extension implements GenericHandler {
public void genericHandle() {
// Do something useful here
}
}
The factory pattern works only if you provide a finite, closed set of implementations:
public class GenericHandlerFactory {
private final GenericHandlerFactory instance = new GenericHandlerFactory();
private GenericHandlerFactory() {}
public GenericHandler getInstance() { return this.instance; }
public GenericHandler createHandler(Class genericHandlerClass) {
GenericHandler result = null;
// Code to create the GenericHandler you want.
return result;
}
}
If users can extend your interface without your knowledge then a factory can't work; you have to stick to the JDBC example.
I am creating a Java library, as a final product in intend to distribute this .jar to developers.
I am "translating" my library from Objective-C where I control which classes header files are available to the developer. In other words I am only exposing to the developer a few classes they can handle.
In my Java library I am using packages and my package has grown quite big. So I decided to separate into different packages my models and controllers. But now the models I wanted to keep private I need to mark as public in order to use from the main package.
My question is does this go against what I was doing in Objective-C ?
For example I have an Event class which is really only used internally and I don't want the user to know about it or think about it. I have another class TimedEvent, which the user can get an instance of an manage.
In my Objective-C, I simply excluded Event class from the library public scope, allowing TimedEvent.
If I am making things more tidy in my library then it seems packages aren't the way. Since now, my main controller is in the main package and all the models are in another package - forced to have a public scope.
Opinions ?
This is possible with Java but there are reasons why (almost) no one does it...
If you put the implementation and the interface into the same package, then you can omit all access modifiers (private, protected, public) from classes and methods to give them "default" or "package" visibility: Only classes in the same package are allowed to see/use them.
Drawback: You'll have to mix API and implementation.
The other approach is to move the implementation into a package *.private.*. No more mixing of API and implementation but malicious users can easily access the implementation - it's just a naming convention. Like a STOP sign: It means something ("be careful") but doesn't actually stop you.
Lastly, you can implement the interface inside of the interface. For example:
public interface IFoo {
String getName();
private static class Foo implements IFoo {
public String getName();
}
public static class FooFactory {
public static IFoo create() { return new Foo(); }
}
}
Ugly, ain't it?
The common approach to controlling exposure of your classes to the world is hiding implementations behind interfaces and factories.
Create an interface for your TimedEvent, and a class for creating instances of TimedEvent interface
Put the interface in the main package, and the factory in a sub-package
Give the factory public visibility
Implement the interface in the sub-package, giving it package visibility
Create an instance of the class implementing the TimedEvent interface in the factory
Here is an example of how you can do it:
package com.my.main;
public interface TimedEvent {
void fire();
}
package com.my.main.events;
import com.my.main;
public class EventFactory {
public TimedEvent makeTimedEvent() { return new TimedEvent (); }
}
// TimedEventImpl has package visibility - it is not public.
class TimedEventImpl implements TimedEvent {
public void fire() {
// Fire a timed event
}
}
The users would access TimedEvent like this:
com.my.main.events.EventFactory f = new com.my.main.events.EventFactory();
com.my.main.TimedEvent evt = f.makeTimedEvent();
evt.fire();
My factory class has a collection of classes, I don't want that dependency, when I add a subclass of SuperClass I need the factory file to stay unchanged
edit:
My factory class has to return all Superclass's subclasses instances, but I can't have a collections of them (or their names) because that's means I will have to change the Factory file whenever I add a new subclass!
package reflection;
public final class Factory {
private final SuperClass[] subclasses_collection
= {new SubClass1(), new SubClass2() /* ...SubClassN */};
public final SuperClass[] getAllSubClasses() {
return subclasses_collection;
}
}
instead of
new SubClass1()
do something like this
Class clazz = Class.forName("SubClass1");
Object subclass1 = clazz.newInstance();
if you want to pass arguments to the constructor, consult this article, section Creating New Objects
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
To find all the subclasses of a given class, I would check out this java world site. It goes through a package, loads the classes, and tests them to see if there are any subclasses.
If you want to search for all subclasses of a class, you can use reflection, as Jeffrey says. However, rather than writing the code to do that yourself, or copy-and-pasting it from some random article, i would use ResolverUtil from the Stripes web framework, which does exactly what you want (and more!).
An alternative to classpath scanning would be to build up a registry at runtime. You could create a base class like this:
public abstract class SuperClass {
private static final Set<Class<? extends SuperClass>> SUB_CLASSES = new HashSet<Class<? extends SuperClass>>();
/* instance initializer */ {
SUB_CLASSES.put(getClass());
}
}
Every subclass of that which is instantiated will add itself to the set of subclasses. Your factory can then use that set. All you have to do is ensure that all the subclasses are instantiated at some point - perhaps using a configuration file, or through startup actions of other parts of your system.