From the java language guide:

   The |java.util.Collections| class has been outfitted with wrapper
   classes that provide guaranteed run-time type safety. They are
   similar in structure to the synchronized and unmodifiable wrappers.
   These “checked collection wrappers” are very useful for debugging.
   Suppose you have a set of strings, |s|, into which some legacy code
   is mysteriously inserting an integer. Without the wrapper, you will
   not find out about the problem until you read the problem element
   from the set, and an automatically generated cast to |String| fails.
   At this point, it is too late to determine the source of the
   problem. If, however, you replace the declaration:

       Set<String> s = new HashSet<String>();
   with this declaration:

       Set<String> s = Collections.checkedSet(new HashSet<String>(), 
String.class);
   the collection will throw a |ClassCastException| at the point where
   the legacy code attempts to insert the integer. The resulting stack
   trace will allow you to diagnose and repair the problem.

Unfortunately the Collection is public and not final in an Entry, so we can't take advantage of this to stop the reference from being changed to a boring old collection.

Anyone want runtime type checks for distributed code?

Peter.

Niclas Hedhman wrote:
On Sat, Dec 18, 2010 at 4:11 PM, Peter <j...@zeus.net.au> wrote:
if you have a field in an Entry declared:

public Collection<String> names;

In bytecode, because of erasure, its type is Collection, this means I can
take from the javaspace and set the field to contain a Collection that
doesn't contain String's and the next time your code accesses it, a
ClassCastException will occur.

That is not correct. For fields, method return values and parameters,
the Type is preserved (ParameterizedType it is called). So for the
above example, do

    Type[] types = names.getClass().getGenericInterfaces();

or something like this for the declaration itself

    Field field = Main.class.getDeclaredField( "names" );
    field.setAccessible( true );
    Type type = field.getGenericType();


In fact, quite a lot of the things that people think are 'erased' are
actually not.

For instance, in a declaration like;

public interface Abc<K,V>

you can even retrieve the variable names of 'K' and 'V' respectively
(those Type are called TypeVariable).


Say what you want about Sun's compromises in the generics system, but
it is far from "just compiler checks".


In my project Qi4j (http://www.qi4j.org), we use this extensively to
do sweet things like;

    Property<String> fullname();  // in an interface

to declare a property instead of getter-setter-mania...


Now, I am not saying that any of this should be deployed into River at
all, just that more things are possible than you might think.


Also Note; There are some small bugs in Sun's JDK1.5 generics
compiler, where some corner cases are handled incorrectly. The ones
that we have found are fixed in 1.6.


Cheers

Reply via email to