Ok, well I just want to make sure you know what I'm talking about. I
understand the need to have a default constructor for injection purposes but
that is not the issue. The issue is with the "normal" constructor calling
init. It should not call init. It might be convenient to put all the
context, request, response object assignments in init for the Spring folk
but it needs to be duplicated in the "normal" constructor also, instead of
just calling init. You must never call non-final methods inside a
constructor.. Here is some test code that explains the bug.
package test;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;
/**
*
* @author jnellis
*/
public class MyResource extends Resource{
// These variables get initialized AFTER init is called!
private String something = "default-value";
private String other; // no default initializer, the default is null.
public MyResource(){
// You can provide this constructor but a Finder won't look at it
// because of the "normal" constructor.
}
public MyResource(Context context, Request request, Response response){
// The call to super happens before the construction of THIS subclass
// object and so when it calls init, it is really calling a method
// of an object that has not been initialized.
super(context,request,response);
}
@Override
public void init(Context context, Request request, Response response){
// call first as Resource.init documentation says.
super.init(context,request,response);
// Now do our initialization stuff.
// The only safe operations are on direct members of the Resource
// class itself, mainly, it seems, to be able to add Variants this
// resource handles.
getVariants().add(new Variant(MediaType.TEXT_PLAIN));
/* The developer says to himself, "oh hey, this is a nice place to
* put my subclass specific stuff too!" BAM! problems start here.
*/
this.something = "apples";
this.other = "oranges";
}
@Override
public Representation getRepresentation(Variant variant){
Representation result = null;
// One would think this prints "apples or oranges" but on my machine
// it prints out "default-value or oranges".
result = new StringRepresentation(something + " or " + other);
// ANY subclass variable with a default initializer will end up
// re-initializing that variable after it has been set in
// the init method.
return result;
}
}
----- Original Message -----
From: "Thierry Boileau" <[EMAIL PROTECTED]>
To: <[email protected]>
Sent: Monday, October 22, 2007 5:02 AM
Subject: Re: When and when not to override Resource.init
Hello Joe,
The "init" method has been introduced in order to satisfy recurrent
requests made by Spring users of the Restlet framework. There is a
need to create resources with the default constructor, instead of the
"normal" one (the one with the 3 parameters). On the other hand
resources need to be instantiated with their context plus the request
and response objects. That's why the Finder tries to invoke the 3
parameters constructor, and if it doesn' exist, invokes the default
constructor then the "init" method.
Having said that, I'm conscious that I've uncompletely answered to
your question... But I've a meeting right now.
best regards,
Thierry Boileau
On 10/22/07, Joe Nellis <[EMAIL PROTECTED]> wrote:
Greetings,
This purposefully overridable method is called from the Resource(Context,
Request, Response) constructor and therefore subclasses that override
init(Context, Request, Response) are in for a big suprise if they try to
do
operations on their own fields in the init method. At this point in
execution, the subclass of Resource has not been initialized and so
default
field intializers have not been called, not even fields declared final.
The
default initializers will be called after init finishes and any subclass
fields set during the init method call will be overwritten with defaults.
This is a gotcha in Joshua Blochs Effective Java pg 80. Constructors of
classes intended to be subclassed should not call overridable methods.
So I think some clarification on when to override init when your class
also
supports the three argument resource constructor (assuming you call
super(context,request,response) first in the constructor.) Why is there
a
three argument constructor? The Finder.createResource calls the default
constructor then calls init afterwards which is ok because all subclasses
have been initialized by then.
Perhaps there is a way with annotations to convey Variants a resource has
representations for as this is what the init method seems to be of value
for, adding variants to the list.
-Joe