I was trying to understand how in Java Service Loader works? I came across this blog:
Could you please help me understand why the author claims:
The implementation must have a public parameterless constructor.
Okay I get the first part. Now a follow up question. I can post it as a follow up a question but thought it would be better to have it as part of the same question.
Consider the java doc:
It says:
In addition, the constructor of a non-private inner member class must be compiled such that it has as its first parameter, an additional implicit parameter representing the immediately enclosing instance (§8.1.3).
So does that mean I cannot externalize a inner class. Please consider the following code:
import java.io.*;
class Y {
class ABC {
ABC() {
System.out.println("ABC Constructor");
}
public void writeExternal(ObjectOutput out)
throws IOException {
System.out.println("ABC.writeExternal");
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
System.out.println("ABC.readExternal");
}
}
public void foo() throws IOException, ClassNotFoundException {
System.out.println("Constructing objects:");
ABC abc = new ABC();
ObjectOutputStream o = new ObjectOutputStream(
new FileOutputStream("InnerClass.out"));
System.out.println("Saving objects:");
o.writeObject(abc);
o.close();
// Now get them back:
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("InnerClass.out"));
System.out.println("Recovering abc:");
// OOPS! Throws an exception:
abc = (ABC)in.readObject();
}
}
public class InnerClass {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("Hello World\n");
Y y = new Y();
System.out.println(y);
y.foo();
}
}
It fails at runtime:
Hello World
Y@6bc7c054
Constructing objects:
ABC Constructor
Saving objects:
Exception in thread "main" java.io.NotSerializableException: Y$ABC
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at Y.foo(InnerClass.java:24)
at InnerClass.main(InnerClass.java:40)
How can I use Externalize class ABC?
Thanks
That's because it's required to create a new instance via reflection.
I guess here's relevant code, line 362:
S p = service.cast(Class.forName(cn, true, loader).newInstance());
Thus it invokes "parameterless" constructor since Class.newInstance()
can only invoke the zero-argument constructor.
Edit:
Actually, it's not required to create a zero-argument constructor for public class
unless you define another constructor.
You don't have to provide any constructors for your class, but you must be careful when doing this. The compiler automatically provides a no-argument, default constructor for any class without constructors.
So, the following code is perfectly correct:
public final class MyServiceImpl implements MyService {
@Override
public long getTime() {
return System.currentTimeMillis();
}
}
Default constructor for MyServiceImpl
will be the same as:
public MyServiceImpl() { }
Since MyServiceImpl
is a public class:
if the class is declared public, then the default constructor is implicitly given the access modifier public
Thus constructor in MyServiceImpl
is redundant.
My guess is that author of the blog post just wanted to make sure that ServiceLoader
will be able to instantiate service provider even when it contains some explicit constructors with arguments.
Conclusion: Service provider should have explicit no-argument constructor only if it contains explicit constructors with arguments. Default constructor will suffice otherwise.