Craig R. McClanahan wrote:
The latter lets any Command lets any Context implementation be passed in, but still provide generic access to the specialized properties without casting. For example, if your Command is passed in a ServletWebContext you can try:

Map map = (Map) context.getAttributes().get("requestScope");

without having to know what Context implementation was used. The things that are accessed through the typesafe property getters and setters are *not* hidden; and you can program solely to the generic Context API if you want to avoid creating dependencies on external Context implementation classes that may or may not be present.

It still doesn't seem like we're answering the question of why does the context have-a-map instead of being-a-map. If Context extended Map, rather than specify a Map property, could not the BaseContext implement the ContextBaseAttributes code directly, instead of as a property? Why is it


context.getAttributes().get("attribute);

instead of

context.get("attribute");

As you've said, we already have a standard interface for a Context ... Map =:) Why are we creating another? (An object with a Map.) Are we just following the example set by ServletContext? That in itself is a fair-enough reason, but I wondered if there were another.

(Another reason might be that isEmpty could conflict with a client attribute (but, conceivably, so could getAttributes)).

Of course, it's not hard to have it both ways. I've been using a ContextMap class as a base, which I'll post as another experimental class. It just implements the Map interface by calling getAttributes. (Should we setup a "whiteboard" or "opt" package for these?)


My problem with this is what it does to implementors of subclasses of such a BaseContext2.

Lots of people can type the idiom for creating a new property on a JavaBean without even thinking about it:

   private String foo;
   public String getFoo() { return this.foo; }
   public void setFoo(String foo) { this.foo = foo; }

and there are lots of IDEs that will do it for you too. Unfortunately, such code won't work in a BaseContext2 subclass; you'd have to change it to:

   public String getFoo() { return ((String) getAttributes().get("foo")); }
   public void setFoo(String foo) { getAttributes().put("foo", foo); }

I can guarantee you that this kind of code doesn't roll straight off your fingertips :-).

Either approach works with Base2. You can mix and match member fields with Map entries. I definitely wouldn't suggest obviating member fields, since it's such a common strategy.


The code I use now to access the Map entries as property values looks like this:

    public String getApplicant() {
        return (String) getField(Tokens.PN_APPLICANT);
    }

    public void setApplicant(String property) {
        putField(Tokens.PN_APPLICANT, property);
    }

And I've the IDE programed to prompt me for the Property and Token names when I need to create one of these, so it's not so hard. (Though, just telling it to encapsulate a field is even easier.)

As it stands, I'm not declaring properties for simple String fields, but only for key fields that are often used in API class and those that need type-safety. So like 80% of the attributes don't need properties anyway.

What I don't like is that getField and putField bypass the reflection mechanism, and so become a backdoor that accesses the underlying attribute map directly. At the very least, this seems to bend encapsulation.

I do believe that it would be better if we didn't compel people to use member fields when there's a perfectly good Map sitting there, but I'm still not thrilled with my implementation.


The other complication would be you can't do this for primitive properties, since you can't store them in the real Map.

I suppose the properties could store them in the wrapper classes and turn them back to primitives on the way back. Since most data access tools don't like primitives, I rarely use them as attributes myself.


-Ted.




--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to