velocity-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Barbara Baughman <baugh...@utdallas.edu>
Subject Re: Defining iterator for #foreach
Date Tue, 19 Oct 2004 00:45:32 GMT
Yes, Velocity 1.4 plays nicely with the java 1.5 compiler and tomcat
5.0 with no adjustments to any piece of the puzzle.

You're right about the Generics not making a difference in the
Velocity template.  My problem was indirect, since in many cases I was
passing arrays of Collection objects to the Velocity context.
Unfortunately, JAVA 1.5 does not allow arrays of Generic-typed
objects, so I chose to find a workaround that would still give me the
advantage of a Generic-typed Collection without having to change all
of my templates.  The MapList did that for me.  Again, you can keep
the code you have and it will still work just fine with JAVA 1.5.
The above was a simple redesign that allowed me to take advantage of
Generics in the java (not template) coding and web session attributes
without changing the templates.

Immutable objects are Object classes whose underlying values cannot be
changed.  The fields are set in the constructor, and there are no
methods that allow them to be changed.  There are also no public,
non-final fields, and all public final fields are immutable classes.
These type of classes are always threadsafe, a good thing.  Clearly,
it's not appropriate for every class, but it is preferable if it can
be done.  So my wrapper class typically is constructed using the
underlying collection once I'm done creating it.  The wrapper class
then doesn't have any methods that allow you to change it or get a
reference to the underlying collection (return a copy instead).

An example of my problem with session attributes is as follows, using
tomcat 5.0:

HashMap<String,String> hm=new HashMap<String,String>();
hm.put("lastname","Baughman");
hm.put("firstname","Barbara");
session.setAttribute("name",hm);

This is NOT legal (generic information is not available at runtime):
HashMap<String,String> name=(HashMap<String,String>)
      session.getAttribute("name");
String lastname=name.get("lastname");
String firstname=name.get("firstname");

This IS legal:
HashMap name=(HashMap) session.getAttribute("name");
String lastname=(String) name.get("lastname");
String firstname=(String) name.get("firstname");

But the last two lines give a warning:unchecked message during
compilation.  The code runs just fine, but I hate having a lot of
warning messages that must be ignored.  Makes me get in the habit of
ignoring all warning messages.

So my wrapper class is:
import java.util.HashMap;
public class StringMap {
   private HashMap<String,String> hm=new HashMap<String,String>();

   public StringMap() {
   }

   public StringMap(HashMap<String,String> hm) {
      this.hm=hm;
   }

   public String get(String key) {
      return hm.get(key);
   }

   ...
}

So this is legal, gives no warnings, and makes pretty code:
session.setAttribute("name", new StringMap(hm));
StringMap sm=(StringMap) session.getAttribute("name");
String lastname=sm.get("lastname");
String firstname=sm.get("firstname");

We're getting off-point with the Velocity list.  Perhaps further
discussion should go off-list.

Barbara Baughman
X2157

On Tue, 19 Oct 2004, Shinobu Kawai wrote:

> Hi Barbara,
>
> Nice to know that Velocity is working with Java 5.  ;)
>
> > I prefer immutable classes because they are threadsafe, can't be
> > changed by the template designer, and follow Joshua Bloch's advice in
> > the book Effective Java (an excellent read, BTW).
> I haven't read the book, so I don't know what's said in it, BUT you
> can make it thread safe by Collections.synchronized*.  Say you have a
> List called list.  You can get what you need by
>   List listForTemplate =
> Collections.unmodifiableList(Collections.synchronizedList(list))
> Okay, so it's a bit annoying.  ;)
>
> > A wrapper class (call it MapList<K,V>) for Vector<SimpleMap<K,V>>
is a
> > lot handier that writing Vector<SimpleMap<K,V>> when I use this
> > particular formulation a lot and pass it to the template designers.
> Ah, you have a List of Map's.  That makes it harder.
>
> > It is also easier for my template designers to use MapList<K,V> than
> > trying to understand the intricacies of Generics in JAVA when the
> > specification gets complicated.
> Actually, I don't think the template designers even care about
> Generics.  All they need to know is, "What are the public methods I
> can use?".  I put a sample at the end of this message.  The Velocity
> template will look the same, using Generics or not.
>
> >  I can also have methods that are more
> > straightforward and return objects that are automatically cast to the
> > proper class.  VERY handy.
> Now that's a good reason.  Readability for the template designers is
> something that needs good care of.
>
> > Even for commonly used, less complicated collections, using a wrapper
> > is sometimes nice.  For example, I have a wrapper for HashMap<String,
> > String> that is immutable and comes in handy for storage as a web
> > session attribute.  It's the only way I can retrieve something that
> > acts like HashMap<String,String> from a session attribute, since you
> > can't cast to a class-with-Generics in Java 1.5.
> Didn't know that.  Can you give an example of when you can't cast it?
> I tried it, but the compiler gave me no errors (only "Unsafe type
> operation" warnings), and running it gave me no ClassCastException's.
>
> >  In my case, it
> > avoids a lot of warning:unchecked compilation messages in my web
> > applications.
> Or is this what you are talking about?
>
> > Probably more than you wanted to know.  Despite writing extra classes
> > (but not many) and a lot of frustration having to sort out what
> > Generics can and cannot do, in the end I think they are a BIG plus for
> > developers who can adapt.
> Of course, I'll bet such developers can adapt to Generics as well.  ;)
>
> Well, here's the sample for Generics and Velocity:
> -- Java code
> VelocityContext context = new VelocityContext();
> List<Map<String, String>> list = new ArrayList<Map<String, String>>();
>
> Map<String, String> map1 = new HashMap<String, String>();
> map1.put("id", "1");
> map1.put("name", "Barbara Baughman");
> list.add(Collections.unmodifiableMap(Collections.synchronizedMap(map1)));
>
> Map<String, String> map2 = new HashMap<String, String>();
> map2.put("id", "2");
> map2.put("name", "Shinobu Kawai");
> list.add(Collections.unmodifiableMap(Collections.synchronizedMap(map2)));
>
> context.put("maplist",
> Collections.unmodifiableList(Collections.synchronizedList(list)));
>
> -- Velocity Template
> #foreach($map in $maplist)
> $map.id:$map.name
> #end
>
> -- Output
> 1:Barbara Baughman
> 2:Shinobu Kawai
>
> Nothing changes for the Template even if you remove the Generics.  :)
>
> Best regards,
> -- Shinobu Kawai
>
> --
> Shinobu Kawai <shinobu.kawai@gmail.com>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: velocity-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: velocity-user-help@jakarta.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-user-help@jakarta.apache.org


Mime
View raw message