4

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

gudge
  • 1,053
  • 4
  • 18
  • 33

3 Answers3

3

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.

javadoc:

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.

lifus
  • 8,074
  • 1
  • 19
  • 24
  • Thanks for the explanation. I have edited my question with one more part. Thanks – gudge Jul 04 '13 at 05:56
  • @gudge Currently, I have nothing to add to [this answer](http://stackoverflow.com/a/9999476/2286990). Is it helpful for you? – lifus Jul 04 '13 at 13:19
  • @gudge But, [in general](http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html), inner class may be instantiated like that: `OuterClass.InnerClass innerObject = outerObject.new InnerClass();`. – lifus Jul 04 '13 at 13:34
  • Thanks for your help. I have accepted your answer. The first part is absolutely clear. The second is not. How do we deserialize a non-static inner class. Thanks. – gudge Jul 04 '13 at 14:12
  • Well, class should implement marker interface `Serializable`([or `Externalizable`](http://stackoverflow.com/a/818093/2286990)) in order to have possibility to be serializable/deserializable thus both inner and outer classes should implement `Serializable` but it's not recommended([see answer I mentioned in my first comment](http://stackoverflow.com/a/9999476/2286990)). So you _may_ implement Serializable like that `class Y implements Serializable` and `class ABC implements Serializable` but it's not a good idea at all. I'm, personally, trying to avoid inner classes in my code. – lifus Jul 04 '13 at 14:27
  • After reading http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html#4539 (Note - Serialization of inner classes) things are much clearer. Thanks – gudge Jul 04 '13 at 16:02
2

You can read the reason on official java doc

The only requirement enforced by this facility is that provider classes must have a zero-argument constructor so that they can be instantiated during loading.

If you declared a constructor with parameter you can not use it properly. Read this article with example

Ravi K Thapliyal
  • 51,095
  • 9
  • 76
  • 89
den ix
  • 102
  • 7
1

Many techniques require a parameterless constructor, so an instance can be created. If there are only constructors that require parameters, the mechanism doesn't know what to pass.

A notable exception to this is the serialization mechanism, which doesn't require a no-param constructor, but that is only because it has some added "magic help" from the VM.

Kayaman
  • 72,141
  • 5
  • 83
  • 121