JDK-6915224 : Compiler type- & existence-checked reflection syntax sugar via new ".." operator
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 7
  • Priority: P5
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2010-01-08
  • Updated: 2011-02-16
  • Resolved: 2010-04-20
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
Add a new operator ".." to allow compile-time type-checked and existence-checked reflection access.

JUSTIFICATION :
1. There is no compile-time typesafe way to gain access via reflection to fields, methods, constructors, annotations, etc.
2. The code to obtain aforementioned artifacts can become verbose.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
See project-coin dev list email:
http://mail.openjdk.java.net/pipermail/coin-dev/2009-December/002638.html

Copied here for convenience:
Proposal:
Compile-time type-checked and existence-checked reflection syntax

  Description:
Introduce a new, double-dot operator ".." to act as syntax sugar for
accessing reflection information with type & existence checking at
compile time.

Concept:
The double-dot operator, meaning "get metamodel artifact", allows for
much more concise reflective access to things you know about at build
time but must use reflection for some reason.  Trust me, it happens
plenty.  The choice of ".." for the operator was that first, ".."
doesn't introduce a new keyword, and second, in filesystems, ".."
usually means "go up a level", which is essentially what we're doing:
going up a level from model to metamodel.  Looking at the examples,
you can see how much less code it is compared to the reflection-based
equivalent, plus if it's typesafe, you get fewer errors when you're
depending on type safety -- that is, at least you knew at compile time
that things were all good.  It still doesn't mean anything at runtime,
and you could get NoSuchMethodException, etc.

Examples:

1. Get the Field object for the field named "bar" in class Foo:
Field bar = Foo..bar;

// current way
Field bar = Foo.class.getDeclaredField("bar");

2. Get the Method object for the method with signature "myMethod(int
a, String y)" defined on class Goo:
Method m = Goo..myMethod(int,String);
// note scope & return type don't matter

// current way
Method m = Goo.class.getDeclaredMethod("myMethod", new
Class[int.class, String.class] {});

3. Get the Class object for the class Snafu.  This is an interesting
case that offers backward compatibility:
Class c = Snafu..class;
// exactly the same as Snafu.class, the ".." operator's insipiration!!

4. Get the @Foo annotation on the Bar class:
Annotation foo = Bar.. at Foo;

// current way
Annotation foo = Bar.class.getAnnotation(Foo.class);

5. Get the @Foo annotation on the field named "blah" in the class Gorp:
Annotation foo = Gorp..blah.. at Foo;

// current way
Annotation foo = Gorp.class.getDeclaredField("blah").getAnnotation(Foo.class);

6. Get the @Foo annotation on the second parameter of the method
"start(int x, @Foo int y, int z)" defined in class Startable:
Annotation foo = Startable..start(int,int.. at Foo,int);

// current way -- no error checking
Annotation[] anns = Startable.class.getMethod("start", new Class[] {
int.class, int.class, int.class }).getParameterAnnotations()[1];
Annotation foo = null;
for (Annotation ann : anns) {
  if (ann.getClass().equals(Foo.class)) {
    foo = ann;
    break; // got it
  }
}
// foo is either null or a reference to the @Foo annotation instance
on the second parameter of the method

7. Get all of the @Foo annotations on all of the parameters of the
methods "start(@Foo int x, int y, @Foo int z)" defined in class
Startable:
Annotation[] foo = Startable..start(int.. at Foo,int.. at Foo,int.. at Foo);
// returns an array with the first @Foo, null, then the last @Foo

// current way left as an exercise to the reader :)

8. Get the @Foo annotation on the "@Foo start(int x, int y, int z)"
method defined in class Startable:
Annotation foo = Startable..start(int,int,int).. at Foo;

// current way
Annotation foo = Startable.class.getDeclaredMethod("start", new
Class[] { int.class, int.class, int.class }).getAnnotation(Foo.class);


Motivation:

The double-dot operator would allow for compile-time type-checked
reflective operations, like those in the persistence APIs.  For
example, in JPA:

@Entity
public class Department {
  @OneToMany(mappedBy = "department") // note string
  Set<Employee> employees;
  //...
}

becomes

@Entity
public class Department {
  @OneToMany(mappedBy = Employee..department) // checked at compile time
  Set<Employee> employees;
  //...
}

It also is beneficial in many other areas.  Use your imagination!  I
can't think of many more (it's late), but Criteria queries come to
mind...


ACTUAL -
See project-coin dev list email:
http://mail.openjdk.java.net/pipermail/coin-dev/2009-December/002638.html

Copied here for convenience:
Proposal:
Compile-time type-checked and existence-checked reflection syntax

  Description:
Introduce a new, double-dot operator ".." to act as syntax sugar for
accessing reflection information with type & existence checking at
compile time.

Concept:
The double-dot operator, meaning "get metamodel artifact", allows for
much more concise reflective access to things you know about at build
time but must use reflection for some reason.  Trust me, it happens
plenty.  The choice of ".." for the operator was that first, ".."
doesn't introduce a new keyword, and second, in filesystems, ".."
usually means "go up a level", which is essentially what we're doing:
going up a level from model to metamodel.  Looking at the examples,
you can see how much less code it is compared to the reflection-based
equivalent, plus if it's typesafe, you get fewer errors when you're
depending on type safety -- that is, at least you knew at compile time
that things were all good.  It still doesn't mean anything at runtime,
and you could get NoSuchMethodException, etc.

Examples:

1. Get the Field object for the field named "bar" in class Foo:
Field bar = Foo..bar;

// current way
Field bar = Foo.class.getDeclaredField("bar");

2. Get the Method object for the method with signature "myMethod(int
a, String y)" defined on class Goo:
Method m = Goo..myMethod(int,String);
// note scope & return type don't matter

// current way
Method m = Goo.class.getDeclaredMethod("myMethod", new
Class[int.class, String.class] {});

3. Get the Class object for the class Snafu.  This is an interesting
case that offers backward compatibility:
Class c = Snafu..class;
// exactly the same as Snafu.class, the ".." operator's insipiration!!

4. Get the @Foo annotation on the Bar class:
Annotation foo = Bar.. at Foo;

// current way
Annotation foo = Bar.class.getAnnotation(Foo.class);

5. Get the @Foo annotation on the field named "blah" in the class Gorp:
Annotation foo = Gorp..blah.. at Foo;

// current way
Annotation foo = Gorp.class.getDeclaredField("blah").getAnnotation(Foo.class);

6. Get the @Foo annotation on the second parameter of the method
"start(int x, @Foo int y, int z)" defined in class Startable:
Annotation foo = Startable..start(int,int.. at Foo,int);

// current way -- no error checking
Annotation[] anns = Startable.class.getMethod("start", new Class[] {
int.class, int.class, int.class }).getParameterAnnotations()[1];
Annotation foo = null;
for (Annotation ann : anns) {
  if (ann.getClass().equals(Foo.class)) {
    foo = ann;
    break; // got it
  }
}
// foo is either null or a reference to the @Foo annotation instance
on the second parameter of the method

7. Get all of the @Foo annotations on all of the parameters of the
methods "start(@Foo int x, int y, @Foo int z)" defined in class
Startable:
Annotation[] foo = Startable..start(int.. at Foo,int.. at Foo,int.. at Foo);
// returns an array with the first @Foo, null, then the last @Foo

// current way left as an exercise to the reader :)

8. Get the @Foo annotation on the "@Foo start(int x, int y, int z)"
method defined in class Startable:
Annotation foo = Startable..start(int,int,int).. at Foo;

// current way
Annotation foo = Startable.class.getDeclaredMethod("start", new
Class[] { int.class, int.class, int.class }).getAnnotation(Foo.class);


Motivation:

The double-dot operator would allow for compile-time type-checked
reflective operations, like those in the persistence APIs.  For
example, in JPA:

@Entity
public class Department {
  @OneToMany(mappedBy = "department") // note string
  Set<Employee> employees;
  //...
}

becomes

@Entity
public class Department {
  @OneToMany(mappedBy = Employee..department) // checked at compile time
  Set<Employee> employees;
  //...
}

It also is beneficial in many other areas.  Use your imagination!  I
can't think of many more (it's late), but Criteria queries come to
mind...



---------- BEGIN SOURCE ----------
No test cases yet.
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Workaround is conventional reflection-based code.