Thanks a lot Joe for this nice demonstration!
I'm totally convinced. I think also the init method must be removed
from the "normal" constructor.
best regards,
Thierry Boileau
On 10/22/07, Joe Nellis <[EMAIL PROTECTED]> wrote:
> 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
> >>
>