Loading generic service implementations via java.util.ServiceLoader - java

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());
}

Related

Java generic interface calling with abstract parameter

I know there's many similar question but I had no luck finding a nice and clean solution if it's possible at all.
I'm implementing a generic interface with subclasses of an abstract type. Problem is that when I'm calling them I either must do type cast in a switch/case or cast type in every method inside interface implementations and I can't figure out a nice and clean approach... I'll better just write down a short example.
// An abstract type with 2 implementations...
public abstract class ObjTypeAbstract {}
public class ObjType extends ObjTypeAbstract {}
public class ScriptType extends ObjTypeAbstract {}
Now the processor for both types with an interface
interface ProcessorInterface<T extends ObjTypeAbstract> {
public void abcMethod(T obj);
}
public class ObjProcessor implements ProcessorInterface<ObjType> {
public void abcMethod(ObjType obj) {}
}
public class ScriptProcessor implements ProcessorInterface<ScriptType> {
public void abcMethod(ScriptType obj) {}
}
What I'm struggling with is a way of calling those processors based on ObjAbstractType. I have a single class that servers as middleware?? or how should I call it.:
Idea was to simple get the right processor via a single switch/case:
public class Processor {
private ProcessorInterface objProcessor = new ObjProcessor();
private ProcessorInterface scriptProcessor = new ScriptProcessor();
public methodAbc(ObjAbstractType obj) {
getProcessor(obj).abcMethod(obj);
}
private ProcessorInterface getProcessor(ObjAbstractType obj) {
if (obj instanceof ObjType) {
return objectProcessor;
} else if (obj instanceof ScriptType) {
return scriptProcessor;
}
return nullProcessor;
}
}
This is what I'd like to have, it also takes care of type casting of objAbstract to actual type for abcMethod, problem is that it results in RawType warning which won't break the code, but I'd like to get rid of it.
And thats where I'm stuck... because if I cast processors to specific type like this:
private ProcessorInterface<ObjType> objProcessor = new ObjProcessor();
private ProcessorInterface<ScriptType> scriptProcessor = new ScriptProcessor();
I won't be able to return an abstract one from getProcessor method so I would have to implement those interfaces with an ObjAbstractType with all it's method and have type casting in all methods of every processor like:
public class ScriptProcessor implements ProcessorInterface<ObjAbstractType> {
public void abcMethod(ObjAbstractType obj) {
ScriptType scr = (ScriptType) obj;
}
}
The other solution might be having a switch/case inside Processor middleware class and cast ObjAbstractType in it, but I'd have to write that switch inside abcMethod and all others or from getProcessor method returns both the Processor and casted ObjType... so I'd have to return some dto containing both. :/
Do you have any ideas / patterns that might help me to get rid of RawType call warning without extending the code with more switch/case or type casts?
Wish you a nice day and I'll be glad for any discussion, David.
You need a way to store the mapping between a ObjTypeAbstract class and a ProcessorInterface instance.
You could use a Map that associates ObjTypeAbstracts (as key) to ProcessorInterfaces (as value).
About the raw type issue, you could use ProcessorInterface<? extends ObjTypeAbstract> for the declared variable but you will still need to perform a unsafe cast to ProcessorInterface<ObjTypeAbstract> to be able to invoke ProcessorInterface.abcMethod() with as parameter a ObjTypeAbstract declared type.
This cast is unavoidable with your actual design.
It could give something like :
public class Processor {
private Map<Class<? extends ObjTypeAbstract>, ProcessorInterface<? extends ObjTypeAbstract >> map = new HashMap<>();
public Processor(){
map.put(ObjType.class, new ObjProcessor());
map.put(ScriptType.class, new ScriptProcessor());
}
public void methodAbc(ObjTypeAbstract obj) {
#SuppressWarnings("unchecked")
ProcessorInterface<ObjTypeAbstract> processorInterface = (ProcessorInterface<ObjTypeAbstract>) map.get(obj.getClass());
processorInterface.abcMethod(obj);
}
}
I don't think there is a substantially more elegant way to get around some form of instanceof logic. However, there should not be need for casting, if you add some types to getProcessor.
public <T extends ObjTypeAbstract> ProcessorInterface<T> getProcessor(Class<T> theClass) {
if (theClass.isAssignableFrom(ObjType.class)) {
return objProcessor;
} else if (theClass.isAssignableFrom(ScriptType.class)) {
return scriptProcessor;
}
return null;
}
This can then be called like this:
ProcessorInterface<ScriptType> scriptProcessor = new Processor().getProcessor(ScriptType.class);
ProcessorInterface<ObjType> objProcessor = new Processor().getProcessor(ObjType.class);

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.

How to bind a generic type using #Provides method in a Guice AbstractModule?

E.g.
public final class SomeModule<T> extends AbstractModule {
private final Class<T> clazz;
public SomeModule(Class<T> clazz) {
this.clazz = clazz;
}
#Provides
T getT(#ExternalAnnotation Any any) {
Any payload = asset.get().getPayload();
return payload.<T>unpack(clazz);
}
}
This will result in an error:
T cannot be used as a key; It is not fully specified.
Neither using TypeLiteral nor Key seems appropriate here, since I want the return type to still be of type T. Thoughts?
With type erasure, Guice will not have enough information from an instance of your module to determine what type you're binding.
Instead, accept a class literal and use it. This example keeps the generics, but if you don't need them for your use-case, you can drop them.
// Warning: Untested. Please revise if needed.
public final class SomeModule<T> extends AbstractModule {
private Class<T> t;
public SomeModule(Class<T> t) {
this.t = t;
}
#Override
public void configure() {
// Uses a class instance rather than reflection, so this is fine.
bind(t).toProvider(new Provider<T>() {
// ... do stuff
});
}
}
See also:
How can I write a generic Guice binding function? (also Google Groups)
Have a common provider for subclasses using Guice?

Referring to a current type using Java generics

I have an interface with a type parameter that allows its conversion into the same type with another type parameter. Like this:
interface Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f);
}
I now want to impose a stricter requirement on the return type: I want the convert method to only return the same type as it was called on. Like this:
class GoodInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be allowed by compiler
// return new BadInterfaze<B>(); // I want this to be a compilation error
return null;
}
}
class BadInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be a compilation error
// return new BadInterfaze<B>(); // I want this to be allowed by compiler
return null;
}
}
The Interfaze interface is under my control, so I can add extra type parameters to it (or its methods) when needed. Do Java generics allow for anything like this?
You can get close by doing this.
public interface Interfaze<T extends Interfaze<T>> {
T convert();
}
Then you can do
public class Main {
public static class Good implements Interfaze<Good> {
#Override
public Good convert() { return new Good(); } // Compiles
}
public static class Bad implements Interfaze<Bad> {
#Override
public Bad convert() { return new Good(); } // Doesn't compile
}
}
This idea of using recursive bounds like this is very common. I personally dislike it as it's very confusing and because it doesn't mix well with inheritance. For example, you can't make a subclass SubGood of Good that implements Interfaze<SubGood> because you can't implement the same generic interface with 2 different type arguments. It only really works if all implementing classes cannot be extended (that's why Enum<E extends Enum<E>> is ok).

Reflective generic type bounds and method chaining

I need to provide a generic interface to be used in separate class hierarchies and would like that interface to support invocation chaining.
I have tried to do this using reflective bounds, but I can't seem to get it to work without having to cast "this" to the desired type. Here is my current approach:
public interface Operable<T extends Operable<T>> {
T prepare();
T operate();
}
public abstract class BaseOperable<T extends Operable<T>> implements Operable<T> {
#Override
public T prepare() {
System.out.println("Preparing...");
// why is this needed? "this" is a BaseOperable that implements Operable<T>
return (T) this;
}
}
public class SpecialOperable<T extends SpecialOperable<T>> extends
BaseOperable<SpecialOperable<T>> {
#Override
public T operate() {
System.out.println("Operation "
+ (Math.random() > 0.5 ? "succeeded" : "failed"));
// this seems to be required
return (T) this;
}
#Override
public T prepare() {
// if I don't override this, the supertype T is used which is
// BaseOperable and hides "specialOp" from chaining
return (T) super.prepare();
}
public T specialOp() {
System.out.println("Doing something special...");
return (T) this;
}
}
The above the following line of code to compile:
mySpecialOperable().prepare().operate().specialOp().operate();
My question is: is there any way to avoid type-casting of every return statement? Is it also possible to not have to override everything at the most specialized level (as is done with the prepare() method)?
The problem is that you are assuming type safety at a place where the compiler cannot determine at compile-time if a casting is legal. This entails the warning you encounter: For making this more clear, assume:
class Foo implements Operable<Foo> { ... } // legal
class Bar implements Operable<Foo> { ... } // not intended, but also legal
The Bar class is not intended to be legal by your abstraction model. You want to implement a self-type but all you can factually require in Java is to demand the extension of a type T that implements a given interface. Thus, extending
class Bar extends BaseOperable<Foo> { ... }
would basically be executed at run time as if you implemented:
class Bar implements Operable<Foo> {
#Override
public Foo prepare() {
System.out.println("Preparing...");
// Why is this needed, you ask? Because you are now expressing this:
return (Foo) this; // this is of type Bar, not Foo
}
...
}
where this is however an instance of Bar but not of Foo. This, of course, causes a ClassCastException and for this possibility, the compiler warns you that static type-safety has failed you and this exception might happen where you would not normally expect it.
You normally avoid this by adding a method like:
protected abstract T self();
which is then implemented by any non-abstract class. As this method is then implemented with a non-generic return type, the static compile check can do its work and forbid you any illegal return types as we observed before. The above prepare method would then be implemented like this:
public T prepare() {
System.out.println("Preparing...");
return self();
}
If you are however working with a closed API that is not implemented by any user and you want to take that short cut (hopefully, you have unit tests that validate against any possible abuse), you can annotate the method with #SupressWarnings("unchecked") to tell the compiler that you are aware of what you are dealing with.
Your problem can be simplified to:
public abstract class AbstractOperable<T extends AbstractOperable<T>> {
public T prepare() {
// Type mismatch: cannot convert from AbstractOperable<T> to T
return this;
}
}
public class OperableImpl extends AbstractOperable<OperableImpl> {
}
Now, consider the following class:
public class OperableImplHack extends AbstractOperable<OperableImpl> {
}
While it fulfills the T extends AbstractOperable<T> contract, this is not T. This is the reason why the compiler can't know if this is T or not in AbstractOperable.
Solution #1:
public abstract class AbstractOperable<T extends AbstractOperable<T>> {
public abstract T getThis();
public T prepare() {
return getThis();
}
}
public class OperableImpl extends AbstractOperable<OperableImpl> {
#Override
public OperableImpl getThis() {
return this;
}
}
Solution #2:
public abstract class AbstractOperable<T extends AbstractOperable<T>> {
protected T that;
public T prepare() {
return that;
}
}
public class OperableImpl extends AbstractOperable<OperableImpl> {
public OperableImpl() {
that = this;
}
}

Categories

Resources