Is there an interface similar to Callable but with arguments? - java

Is there an interface in Java similar to the Callable interface, that can accept an argument to its call method?
Like so:
public interface MyCallable<V> {
V call(String s) throws Exception;
}
I would rather avoid creating a new type if there already exists something that I can use. Or is there a better strategy to having multiple clients implement and plug in a callable routine?
Copied from here http://www.programmingforums.org/thread27905.html

Since Java 8 there is a whole set of Function-like interfaces in the java.util.function package. The one you're asking for specifically is simply Function.
Prior to Java 8, there was no general-purpose, built-in interface for this, but some libraries provided it.
For example Guava has the Function<F,T> interface with the method T apply(F input). It also makes heavy use of that interface in several places.

at first it thought that this is done with an interface but then i found that it should be done using an abstract class.
i have solved it this way:
edit: lately i just use this:
public static abstract class callback1<T>{
public abstract void run(T value);
}
public static abstract class callback2<T,J>{
public abstract void run(T value,J value2);
}
public static abstract class callback3<T,J,Z>{
public abstract void run(T value,J value2,Z value3);
}
public static abstract class callbackret1<R,T>{
public abstract R run(T value);
}
public static abstract class callbackret2<R,T,J>{
public abstract R run(T value,J value2);
}
public static abstract class callbackret3<R,T,J,Z>{
public abstract R run(T value,J value2,Z value3);
}
CallBack.java
public abstract class CallBack<TRet,TArg> {
public abstract TRet call(TArg val);
}
define method:
class Sample2
{
CallBack<Void,String> cb;
void callcb(CallBack<Void,String> CB)
{
cb=CB; //save the callback
cb.call("yes!"); // call the callback
}
}
use method:
sample2.callcb(new CallBack<Void,String>(){
#Override
public Void call(String val) {
// TODO Auto-generated method stub
return null;
}
});
two arguments sample: CallBack2.java
public abstract class CallBack2<TRet,TArg1,TArg2> {
public abstract TRet call(TArg1 val1,TArg2 val2);
}
notice that when you use Void return type you have to use return null;
so here is a variation to fix that because usually callbacks do not return any value.
void as return type: SimpleCallBack.java
public abstract class SimpleCallBack<TArg> {
public abstract void call(TArg val);
}
void as return type 2 args: SimpleCallBack2.java
public abstract class SimpleCallBack<TArg1,TArg2> {
public abstract void call(TArg1 val1,TArg2 val2);
}
interface is not useful for this.
interfaces allow multiple types match same type. by having a shared predefined set of functions.
abstract classes allow empty functions inside them to be completed later. at extending or instantiation.

I've had the same requirement recently. As others have explained many libs do provide 'functional' methods, but these do not throw exceptions.
An example of how some projects have provided a solution is the RxJava library where they use interfaces such as ActionX where 'X' is 0 ... N, the number of arguments to the call method. They even have a varargs interface, ActionN.
My current approach is to use a simple generic interface:
public interface Invoke<T,V> {
public T call(V data) throws Exception;
// public T call(V... data) throws Exception;
}
The second method is preferable in my case but it exhibits that dreaded "Type safety: Potential heap pollution via varargs parameter data" in my IDE, and that is a whole other issue.
Another approach I am looking at is to use existing interfaces such as java.util.concurrent.Callable that do not throw Exception, and in my implementation wrap exceptions in unchecked exceptions.

Since Java 1.8 there is a Supplier<T> interface. It has a get() method instead of call() and it does not declare any Exception thrown.

The answer is ambiguous. Strictly speaking, that is, "for the same purpose of the Callable interface", there is not.
There are similar classes, and depending on what you want, they may or may not be convenient. One of them is the SwingWorker. However, as the name implies, it was designed for use within the Swing framework. It could be used for other purposes, but this would be a poor design choice.
My best advice is to use one provided by an extension library (Jakarta-Commons, Guava, and so on), depending on what libraries you already use in your system.

Normally arguments are not required as the method can have any number of arguments in its constructor.
final int i = 5;
final String word = "hello";
Future<String> future = service.submit(new Callable<String>() {
public String call() {
return word + i;
}
});
In this example i and word have been used, but you can "pass" any number of parameters.

I just had the same issue. you can wrap any method to return a callable, and execute it's returned value.
i.e.
main {
Callable<Integer> integerCallable = getIntegerCallable(400);
Future<Integer> future = executor.submit(integerCallable);
}
private Callable<Integer> getIntegerCallable(int n) {
return () -> {
try {
TimeUnit.SECONDS.sleep(n);
return 123;
} catch (InterruptedException e) {
throw new IllegalStateException("task interrupted", e);
}
};
}

Define an interface like so:
interface MyFunction<I, O> {
O call(I input);
}
Define a method:
void getOrderData(final Function<JSONArray, Void> func){
...
JSONArray json = getJSONArray();
if(func!=null) func.call(json);
}
Usage example:
//call getOrderData somewhere in your code
getOrderData(new Function<JSONArray, Void>() {
#Override
public Void call(JSONArray input) {
parseJSON(input);
return null;
}
});

Related

Can I define the Negatable interface in Java?

Asking this question to clarify my understanding of type classes and higher kinded types, I'm not looking for workarounds in Java.
In Haskell, I could write something like
class Negatable t where
negate :: t -> t
normalize :: (Negatable t) => t -> t
normalize x = negate (negate x)
Then assuming Bool has an instance of Negatable,
v :: Bool
v = normalize True
And everything works fine.
In Java, it does not seem possible to declare a proper Negatable interface. We could write:
interface Negatable {
Negatable negate();
}
Negatable normalize(Negatable a) {
a.negate().negate();
}
But then, unlike in Haskell, the following would not compile without a cast (assume MyBoolean implements Negatable):
MyBoolean val = normalize(new MyBoolean()); // does not compile; val is a Negatable, not a MyBoolean
Is there a way to refer to the implementing type in a Java interface, or is this a fundamental limitation of the Java type system? If it is a limitation, is it related to higher-kinded type support? I think not: it looks like this is another sort of limitation. If so, does it have a name?
Thanks, and please let me know if the question is unclear!
Actually, yes. Not directly, but you can do it. Simply include a generic parameter and then derive from the generic type.
public interface Negatable<T> {
T negate();
}
public static <T extends Negatable<T>> T normalize(T a) {
return a.negate().negate();
}
You would implement this interface like so
public static class MyBoolean implements Negatable<MyBoolean> {
public boolean a;
public MyBoolean(boolean a) {
this.a = a;
}
#Override
public MyBoolean negate() {
return new MyBoolean(!this.a);
}
}
In fact, the Java standard library uses this exact trick to implement Comparable.
public interface Comparable<T> {
int compareTo(T o);
}
In general, no.
You can use tricks (as suggested in the other answers) that will make this work, but they do not provide all of the same guarantees that the Haskell typeclass does. Specifically, in Haskell, I could define a function like this:
doublyNegate :: Negatable t => t -> t
doublyNegate v = negate (negate v)
It is now known that the argument and return value of doublyNegate are both t. But the Java equivalent:
public <T extends Negatable<T>> T doublyNegate (Negatable<T> v)
{
return v.negate().negate();
}
doesn't, because Negatable<T> could be implemented by another type:
public class X implements Negatable<SomeNegatableClass> {
public SomeNegatableClass negate () { return new SomeNegatableClass(); }
public static void main (String[] args) {
new X().negate().negate(); // results in a SomeNegatableClass, not an X
}
This isn't particularly serious for this application, but does cause trouble for other Haskell typeclasses, e.g. Equatable. There is no way of implementing a Java Equatable typeclass without using an additional object and sending an instance of that object around wherever we send values that need comparing, (e.g:
public interface Equatable<T> {
boolean equal (T a, T b);
}
public class MyClass
{
String str;
public static class MyClassEquatable implements Equatable<MyClass>
{
public boolean equal (MyClass a, MyClass b) {
return a.str.equals(b.str);
}
}
}
...
public <T> methodThatNeedsToEquateThings (T a, T b, Equatable<T> eq)
{
if (eq.equal (a, b)) { System.out.println ("they're equal!"); }
}
(In fact, this is exactly how Haskell implements type classes, but it hides the parameter passing from you so you don't need to figure out which implementation to send where)
Trying to do this with just plain Java interfaces leads to some counterintuitive results:
public interface Equatable<T extends Equatable<T>>
{
boolean equalTo (T other);
}
public MyClass implements Equatable<MyClass>
{
String str;
public boolean equalTo (MyClass other)
{
return str.equals(other.str);
}
}
public Another implements Equatable<MyClass>
{
public boolean equalTo (MyClass other)
{
return true;
}
}
....
MyClass a = ....;
Another b = ....;
if (b.equalTo(a))
assertTrue (a.equalTo(b));
....
You'd expect, due to the fact that equalTo really ought to be defined symmetrically, that if the if statement there compiles, the assertion would also compile, but it doesn't, because MyClass isn't equatable with Another even though the other way around is true. But with a Haskell Equatable type class, we know that if areEqual a b works, then areEqual b a is also valid. [1]
Another limitation of interfaces versus type classes is that a type class can provide a means of creating a value which implements the type class without having an existing value (e.g. the return operator for Monad), whereas for an interface you must already have an object of the type in order to be able to invoke its methods.
You ask whether there is a name for this limitation, but I'm not aware of one. It's simply because type classes are actually different to object-oriented interfaces, despite their similarities, because they are implemented in this fundamentally different way: an object is a subtype of its interface, thus carries around a copy of the interface's methods directly without modifying their definition, while a type class is a separate list of functions each of which is customised by substituting type variables. There is no subtype relationship between a type and a type class that has an instance for the type (a Haskell Integer isn't a subtype of Comparable, for example: there simply exists a Comparable instance that can be passed around whenever a function needs to be able to compare its parameters and those parameters happen to be Integers).
[1]: The Haskell == operator is actually implemented using a type class, Eq ... I haven't used this because operator overloading in Haskell can be confusing to people not familiar with reading Haskell code.
I interpret the question as
How can we implement ad-hoc polymorphism using typeclasses in Java?
You can do something very similar in Java, but without the type safety guarantees of Haskell - the solution presented below can throw errors at runtime.
Here is how you can do it:
Define interface that represents the typeclass
interface Negatable<T> {
T negate(T t);
}
Implement some mechanism that allows you to register instances of the typeclass for various types. Here, a static HashMap will do:
static HashMap<Class<?>, Negatable<?>> instances = new HashMap<>();
static <T> void registerInstance(Class<T> clazz, Negatable<T> inst) {
instances.put(clazz, inst);
}
#SuppressWarnings("unchecked")
static <T> Negatable<T> getInstance(Class<?> clazz) {
return (Negatable<T>)instances.get(clazz);
}
Define the normalize method that uses the above mechanism to get the appropriate instance based on the runtime class of the passed object:
public static <T> T normalize(T t) {
Negatable<T> inst = Negatable.<T>getInstance(t.getClass());
return inst.negate(inst.negate(t));
}
Register actual instances for various classes:
Negatable.registerInstance(Boolean.class, new Negatable<Boolean>() {
public Boolean negate(Boolean b) {
return !b;
}
});
Negatable.registerInstance(Integer.class, new Negatable<Integer>() {
public Integer negate(Integer i) {
return -i;
}
});
Use it!
System.out.println(normalize(false)); // Boolean `false`
System.out.println(normalize(42)); // Integer `42`
The main drawback is that, as already mentioned, the typeclass instance lookup can fail at runtime, not at compile-time (as in Haskell). Using a static hash map is suboptimal too, because it brings all the problems of a shared global variable, this could be mitigated with more sophisticated dependency injection mechanisms. Automatically generating typeclass instances from other typeclass instances, would require even more infrastructure (could be done in a library). But in principle, it implements ad-hoc polymorphism using typeclasses in Java.
Full code:
import java.util.HashMap;
class TypeclassInJava {
static interface Negatable<T> {
T negate(T t);
static HashMap<Class<?>, Negatable<?>> instances = new HashMap<>();
static <T> void registerInstance(Class<T> clazz, Negatable<T> inst) {
instances.put(clazz, inst);
}
#SuppressWarnings("unchecked")
static <T> Negatable<T> getInstance(Class<?> clazz) {
return (Negatable<T>)instances.get(clazz);
}
}
public static <T> T normalize(T t) {
Negatable<T> inst = Negatable.<T>getInstance(t.getClass());
return inst.negate(inst.negate(t));
}
static {
Negatable.registerInstance(Boolean.class, new Negatable<Boolean>() {
public Boolean negate(Boolean b) {
return !b;
}
});
Negatable.registerInstance(Integer.class, new Negatable<Integer>() {
public Integer negate(Integer i) {
return -i;
}
});
}
public static void main(String[] args) {
System.out.println(normalize(false));
System.out.println(normalize(42));
}
}
You're looking for generics, plus self typing. Self typing is the notion of generic placeholder that equates to the class of the instance.
However, self typing doesn't exist in java.
You can get close with generics, but it's clunky:
public interface Negatable<T> {
public T negate();
}
Then
public class MyBoolean implements Negatable<MyBoolean>{
#Override
public MyBoolean negate() {
//your impl
}
}
Some implications for implementers:
They must specify themselves when they implement the interface, e.g. MyBoolean implements Negatable<MyBoolean>
Extending MyBoolean would require one to override the negate method again.

Java 8 method references : validation of methods at compile time

I'd like to use the new method references of Java 8 to provide more validation of some code at compile time.
Let's say I have a validateMethod method which requires one parameter : a "method" to be validated. For example :
validateMethod(foo, "methodA");
Here, the method would validate that foo#methodA() exists, at runtime.
Using method references, I'd like to be able to do :
validateMethod(foo::methodA);
So the existence of the method would be validated at compile time.
The problem is that it seems method references have to be assigned to a functional interface. For example, this :
Object dummy = foo::methodA;
Generates the error : "The target type of this expression must be a functional interface".
If I create a functional interface that has a compatible signature with the methodA method, it works :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
MyFunctionalInterface dummy = foo::methodA;
Now the existence of foo#methodA() is validated at compile time, which is what I want!
But...
Let's say validateMethod doesn't know the signature of the method it has to validate. Is it still possible to implement it then?
Let's pretend we don't care about ambiguity and overloaded methods. Is it possible in Java 8 to implement some kind of method which would trigger the validation of any method reference?
For example :
public class Foo
{
public String methodA()
{
return "methodA";
}
public String methodB(String str)
{
return "methodB";
}
public String methodC(String str, int nbr)
{
return "methodC";
}
}
Foo foo = new Foo();
validateMethod(foo::methodA); // Compile
validateMethod(foo::methodB); // Compile
validateMethod(foo::methodC); // Compile
validateMethod(foo::methodD); // Error!
Would it be possible to implement validateMethod in such a way that any method reference would be accepted, so the existence of the method would be validated at compile time?
I tried :
public void validateMethod(Object obj){}
But it doesn't work : "The target type of this expression must be a functional interface"
This would work :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
public void validateMethod(MyFunctionalInterface param){}
But only for methodA of the Foo class, because its signature (no parameter) is compatible with the functional interface's method signature!
Would it be possible to implement the functional interface MyFunctionalInterface in such a way that any method reference would be a valid parameter and therefore would be validated at compile time?
Any other ways you see to validate the existence of a method at compile time?
You seem to be trying to use method references, which are really the short-hands for lambda expressions, as method literals, which are the syntactic references to methods (much like Foo.class is the syntactic reference to class instance of Foo). These two are not the same, and this is the reason for the impedance you encounter. Things you try are the abuse of language feature which javac compiler utterly resists.
Unfortunately, there is no method literals in Java, so you will have to describe the method by other means, e.g. Reflection, MethodHandles.Lookup, etc. I think it is very easy to come up with the reflective checker for this kind of thing, or even build up the annotation processor to check the existence of given methods in compile time.
You could try something like the following:
public class Validate {
public String methodA() { return "methodA"; }
public String methodB(String s) { return "methodB"; }
public String methodC(String s, int n) { return "methodC"; }
public static void main(String[] args) {
Validate foo = new Validate();
validateMethod(foo::methodA);
validateMethod(foo::methodB);
validateMethod(foo::methodC);
}
private interface Func0 { void method(); }
private interface Func1<T> { void method(T t); }
private interface Func2<T, U> { void method(T t, U u); }
private interface Func3<T, U, V> { void method(T t, U u, V v); }
public static void validateMethod(Func0 f) { }
public static <T> void validateMethod(Func1<T> f) { }
public static <T, U> void validateMethod(Func2<T, U> f) { }
public static <T, U, V> void validateMethod(Func3<T, U, V> f) { }
}
But you'll need to provide an interface and an overload of validateMethod for every arity of method you need to validate. Also, it will not work if the method to validate is overloaded, unless you add an explicit cast:
// if there are two methodA's:
public String methodA() { return "methodA"; }
public String methodA(long x) { return "methodA"; }
validateMethod(foo::methodA); // this doesn't work
validateMethod((Func0)foo::methodA); // this does
validateMethod((Func1<Long>)foo::methodA); // so does this
would interface Method { public Object runMethod(Object... args); } work? the only potential problem i see is methods that deal with primitive types, but perhaps they could be upcast automatically to Double's / Long's, dont really have a running java8 compiler atm.

Generics, Interface puzzle, what is the advantage of declaring interface like this?

In my project I see the interface like this. All the model extend the interface. I am wondering what is the use ?
public interface IModel {
<T> T modelTo(Class<T> clazz);
}
public interface IPerson extends IModel {
public String getFirstName();
public void setFirstName(String firstName);
public String getMiddleName();
public void setMiddleName(String middleName);
}
Then in some places in the code I see like
#Override
public void modelJoin(IModel parent, IModel sample) {
//Some code
IPerson sample= sample.modelTo(IPerson.class);
IPerson person = parent.modelTo(IPerson.class);
//Some code
}
Can you explain me the insight of it ?
It looks like the use of the Adapter pattern. The idea is to create a "view" of a class given another class, or adapt one type of class to act as another.
A simple real world example can be that of electrical sockets. In different countries different types of sockets are used. So you use adapters to plug in your phone into an electrical socket it normally doesn't "recognize".
This can of course be modelled using object oriented programming and the adapter pattern as well. Using your IModel interface but naming it IAdaptable it could be used like this.
public interface IAdaptable {
<T> T adaptAs(Class<T> clazz);
}
public interface IChargeAmerican { void chargePhoneInAmerica(); }
public interface IChargeEurope { void chargePhoneInEurope(); }
public class EuropeanSocket implements IAdaptable, IChargeEurope {
public <T> T adaptAs(Class<T> clazz) {
if (clazz.equals(IChargeAmerican.class)) {
return new EuropeanSocketToAmericanSocketAdapter(this);
}
throw new RuntimeException("unknown");
}
public void chargePhoneInEurope() {
;
}
}
public class AmericanSocket implements IChargeAmerican {
public void chargePhoneInAmerica() {
;
}
}
public class EuropeanSocketToAmericanSocketAdapter implements IChargeAmerican {
private EuropeanSocket socket;
public EuropeanSocketToAmericanSocketAdapter(EuropeanSocket socket) {
this.socket = socket;
}
public void chargePhoneInAmerica() {
socket.chargePhoneInEurope();
}
}
And to use it one would simply adapt the european socket to an american one, sort of like plugging in an adapter in between the two.
public void foo() {
EuropeanSocket europe = new EuropeanSocket();
IChargeAmerican murica = europe.adaptAs(IChargeAmerican.class);
murica.chargePhoneInAmerica();
}
This example shows how the adaptAs method creates a link between the two interfaces IChargeAmerican and IChargeEurope. Even though they don't have anything in common the adapter can act as they do.
Now, the EuropeanSocket implements the IAdaptable interface in order to "convert" itself to another known socket. Usually though the class should not be responsible for this. As the example at wikipedia shows, a factory or provider is better suited for this.
I think that you ask why the method signature
<T> T modelTo(Class<T> clazz);
is used.
The parameter clazz is used to have the type information inside the method implemented. You can then access the type information very easy.
You can then create an object and return it from the implemented method that has the given class.
The method signature looks a bit clumsy but is helpful as the generic information is missing after compilation (type erasure) and the parameters give you the possibility to access the type information (and thereforethe expected return type).
I can imagine it may have been made that way to allow type casting by passing a Class object as a parameter of other methods calling the modelTo(Class clazz) method, or in other words : having other methods casting IModel objects to any class without even knowing which class they will cast it into (nothing even prevents from passing a Class instance to this method which isn't even a subtype of IModel...)
It would be interesting to know how this modelTo method is implemented. Is there a single, final implementation in an abstract skeleton class ? How does it respond to errors (like passing null as the clazz parameter, or triggering a ClassCastException) ? In other words : could this be an attempt to encapsulate all class casts into a single method, to replace ClassCastExceptions with a custom Exception or something like that ? (ClassCastException being a RuntimeException, it could have been a way to make sure a checked exception is thrown instead to enforce explicit exception handling everywhere in the code, I've already seen projects using such an approach...)

Calling a static method using generic type

No static member can use a type parameter, but is it possible to call a static member using the generic type parameter? For example:-
abstract class Agent<A>{
void callAgent();
Agent(){
A.add();
}
}
Here add() is a static method.
There are some C# questions and answers on a similar topic but I'm not too sure how to go about it in Java.
No you cannot do it if A is a generic type. (Bozho answered to fast :) and probably thought A was concrete type.
What will work is the following.
abstract class Agent extends Blah<ConcreteA>{
void callAgent();
Agent() {
ConcreteA.add();
}
}
but it's probably not what you want to do.
After reading your comments it sounds like what you really want to do is:
abstract class Agent<A extends SomeClassThatSupportsAdd> {
void callAgent();
protected abstract A createNew();
Agent() {
A a = createNew();
A.add();
}
}
Your subclasses will have to override createNew().
If you still do not like that you can take a look at AspectJ which will allow you to do some constructor magic (see how spring does #Configurable) but that gets far trickier and complicates things.
Another option is Scala. Java does not do inheritance on static methods so you can't get parameterized modules (groups of functions in some languages this is called a functor ... ocaml). However Scala supports a singleton "object" that does allow for parametric functional polymorphic inheritance.
No, you cannot. The compiler does not know A (which resolves to Object) has the add method.
And you shouldn't need to invoke static methods on generic types in the first place. If you want specific behaviour for each type, define it as non-static, use extends BaseClass in the generics declaration, and invoke it.
Technically, you can also invoke a static method that way, but it's ugly:
class Base {
public static void add() { }
}
class Foo<A extends Base> {
void bar() {
A a = null; // you can't use new A()!
a.add();
}
}
This is not possible because the A type will not necessarily contain an add() method. The compiler will not permit this, because it can't guarantee that it will work.
In fact, you can invoke a static method on a type parameter (although it isn't done dynamically).
Try this:
public class Main<T extends Collections> {
public static void main(String[] args) {
new Main<>().foo();
}
void foo() {
List<Integer> list = Arrays.asList(2, 3, 1);
T.sort(list);
System.out.println(list);
}
}
I have no idea why the language designers decided it was a good idea to allow this.
It is handy to get a value from an enum you don't know beforehand.
public static <T extends Enum<T>> T enumFromName(String name, Class<T> clazz) {
return StringUtils.isEmpty(value) ? null : T.valueOf(clazz, name);
}
Having:
enum ProductType { FOOD, ELECTRONICS, ... }
You can do:
ProductType p = enumFromName("FOOD", ProductType.class);
I guess you can also take advantage of this in your own classes, although I would not recommend using static too much.
You can use reflection for calling static method of class T. For example:
public Agent<T>{
private final Class<T> clazz;
public Agent(Class<T> clazz){
this.clazz = clazz;
executeAddMethodOfGenericClass();
}
public void executeAddMethodOfGenericClass() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = clazz.getMethod("add");
method.invoke(null);
}
}
But i can get exception. Be careful.

Loading generic service implementations via java.util.ServiceLoader

I've stumbled upon some inconvenience the other day using java.util.ServiceLoader and some questions formed in me.
Suppose I have a generic service:
public interface Service<T> { ... }
I couldn't explicitly tell ServiceLoader to load only implementations with a specific generic type.
ServiceLoader<Service<String>> services =
ServiceLoader.load(Service.class); // Fail.
My question is: what are reasonable ways to use ServiceLoader to safely load implementations of a generic service?
After asking the above question and before Paŭlo's answer I've managed to come up with a solution.
public interface Service<T> { ...
// true if an implementation can handle the given `t' type; false otherwise.
public boolean canHandle(Class<?> t) { ...
public final class StringService implements Service<String> { ...
#Override public boolean canHandle(Class<?> t) {
if (String.class.isAssignableFrom(type))
return true;
return false;
}
public final class DoubleService implements Service<Double> { ...
// ...
public final class Services { ...
public static <T> Service<T> getService(Class<?> t) {
for (Service<T> s : ServiceLoader.load(Service.class))
if (s.canServe(t))
return s;
throw new UnsupportedOperationException("No servings today my son!");
}
Changing boolean canServe(Class<?> t) to boolean canServe(Object o) and also changing <T> Service<T> getService(Class<?> t) in the same manner can be more dynamic (I'm using the latter for myself as I had a method boolean canHandle(T t) on my interface in the beginning.)
The problem here is that the service loader is using a file listing all implementations of a given class/interface, the file being named by the interfaces name. It was not foreseen to put the type parameter into this file name, and it also is not really possible to pass generic types as Class objects.
So, you here can only get your generic services of any types, and then inspect their class object to see if it is a subtype of Service<String>.
Something like this:
class Test{
public Service<String> getStringService() {
// it is a bit strange that we can't explicitely construct a
// parametrized type from raw type and parameters, so here
// we use this workaround. This may need a dummy method or
// variable if this method should have another return type.
ParametrizedType stringServiceType =
(ParametrizedType)Test.class.getMethod("getStringService").getGenericReturnType();
ServiceLoader<Service<?>> loader = ServiceLoader.load(Service<?>.class);
for(Service<?> service : loader) {
if(isImplementing(service.getClass(), stringServiceType)) {
#SuppressWarnings("unchecked")
Service<String> s = (Service)service;
return s;
}
}
}
public boolean isImplementing(Class<?> candidate, ParametrizedType t) {
for(Type iFace : candidate.getGenericInterfaces()) {
if(iFace.equals(t)) {
return true;
}
if(iFace instanceof ParametrizedType &&
((ParametrizedType)iFace).getRawType().equals(t.getRawType())) {
return false;
}
}
return false;
}
}
This is not tested, and may need to be extended to also search interfaces extended by the interfaces our class implements directly, and interfaces implemented by our (generic) superclass.
And of course, this can only find classes like
class Example implements Service<String> { ...}
not something like
class Example<X> implements Service<X> { ... }
where Example<String> might be a valid implementation of your service.
You could also just copy the ServiceLoader class file and remove the generic type argument from the load() method, causing it to always work. You'll just need to override the warnings.
public static <S> ServiceLoader load(final Class<S> service)
{
return load(service, Thread.currentThread().getContextClassLoader());
}

Categories

Resources