Go Back   Velocity Reviews > Newsgroups > Java
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

Java - Generics and forName()

 
Thread Tools Search this Thread
Old 01-31-2006, 12:31 AM   #1
Default Re: Generics and forName()


"Jacob" <> wrote in message
news:MKidnQIqzM-...
> If I have this class:
>
> class A {
> public A(String a);
> }
>
> Is it possible to make an instance through reflection without getting a
> compiler warning (java 1.5)?
>
> The following gives an unchecked warning in the first line due to the
> forced cast. Using "?" just postpone the the problem:
>
> Class<A> clazz = (Class<A>) Class.forName("A");
> Constructor<A> ctor = clazz.getConstructor(String.class);
> A a = ctor.newInstance("hello world");
>
> The problem is that in my organization we treat warnings as errors and
> the above simply isn't doable within such a regime.
>
> What is the workaround?
>
> (And why whould all the above be possible (by Class<?> and

Class.newInstance()),
> if just the constructor didn't take any arguments?)
>
> Thanks!
>


Hello Jacob,
I have seen this question quite a number of times, which prompted me to add
it to my FAQ.
http://jqa.tmorris.net/GetQAndA.acti...owAnswers=true

I have also included a code sample below that demonstrates what you want to
achieve.
As a note, if you have a policy of not being permitted to have compile-time
warnings, it may be in your interest to learn about generics.

Also note that there are some valid use cases that force a compile-time
warning, due to the contrived nature of the Java generics implementation, so
you may seek to have this policy reviewed. These forced use cases are the
result of the introduction of failure to maintain a conversion between
arrays and parameterised types (without a warning) - as an example, take a
look at the java.util.ArrayList implementation, which is backed by an
array - you will note that there is a forced compile-time warning. You
discover these nitty details when you implement the spec. after a JSR
"expert" group has been onto the case I did make this issue known well
before the spec. was released, but the most plausible response I got was
"oops".

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import static java.lang.Class.forName;

class X
{
X(final String s)
{

}
}

final class Main
{
private Main() throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
}

public static void main(final String... args) throws
ClassNotFoundException,
NoSuchMethodException,
InstantiationException,
IllegalAccessException,
InvocationTargetException
{
final Class<?> c = forName("X");
final Class<? extends X> xc = c.asSubclass(X.class);
final Constructor<? extends X> ctor =
xc.getConstructor(String.class);
final X x = ctor.newInstance(args[0]);
}
}


--
Tony Morris
http://tmorris.net/

Java Questions and Answers
http://jqa.tmorris.net/





Tony Morris
  Reply With Quote
Old 01-31-2006, 08:35 AM   #2
Jacob
 
Posts: n/a
Default Generics and forName()

If I have this class:

class A {
public A(String a);
}

Is it possible to make an instance through reflection without getting a
compiler warning (java 1.5)?

The following gives an unchecked warning in the first line due to the
forced cast. Using "?" just postpone the the problem:

Class<A> clazz = (Class<A>) Class.forName("A");
Constructor<A> ctor = clazz.getConstructor(String.class);
A a = ctor.newInstance("hello world");

The problem is that in my organization we treat warnings as errors and
the above simply isn't doable within such a regime.

What is the workaround?

(And why whould all the above be possible (by Class<?> and Class.newInstance()),
if just the constructor didn't take any arguments?)

Thanks!

  Reply With Quote
Old 01-31-2006, 11:42 AM   #3
Chris Uppal
 
Posts: n/a
Default Re: Generics and forName()

Jacob wrote:

> The problem is that in my organization we treat warnings as errors and
> the above simply isn't doable within such a regime.


Ha ha! Then you loose!

I'm not sure about the particular example you mention -- I don't know a
(working) way to avoid the warning myself, but that doesn't mean there isn't
one[*].

But the real problem here is not javac, but the way your organisation works.
Find the person responsible for this absurd rule and fire him/her (and,
perhaps, also his/her manager). Or if the condition was imposed by a customer,
find the salesthing which accepted that clause in the contract and fire it.

-- chris
[*] Well, I suppose you could compile with -source 1.4



  Reply With Quote
Old 01-31-2006, 01:43 PM   #4
Roedy Green
 
Posts: n/a
Default Re: Generics and forName()


On Tue, 31 Jan 2006 09:35:32 +0100, Jacob <> wrote,
quoted or indirectly quoted someone who said :

>The following gives an unchecked warning in the first line due to the
>forced cast. Using "?" just postpone the the problem:
>
> Class<A> clazz = (Class<A>) Class.forName("A");
> Constructor<A> ctor = clazz.getConstructor(String.class);
> A a = ctor.newInstance("hello world");


Unchecked means the compiler cannot guarantee safety at compile time.
The truth is it can't. It has absolutely no idea what A will be/do. If
you want the compiler to be able to check, it wants to see the code at
compile time.

Further this code makes no sense to me. If type A is known at compile
time, why are you dicking around with Class.forName. You only do that
when you DON'T know the class name, just an interface it implements..
--
Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.
  Reply With Quote
Old 01-31-2006, 03:12 PM   #5
Ian Pilcher
 
Posts: n/a
Default Re: Generics and forName()

Jacob wrote:
> If I have this class:
>
> class A {
> public A(String a);
> }
>
> Is it possible to make an instance through reflection without getting a
> compiler warning (java 1.5)?
>
> The following gives an unchecked warning in the first line due to the
> forced cast. Using "?" just postpone the the problem:
>
> Class<A> clazz = (Class<A>) Class.forName("A");
> Constructor<A> ctor = clazz.getConstructor(String.class);
> A a = ctor.newInstance("hello world");
>
> The problem is that in my organization we treat warnings as errors and
> the above simply isn't doable within such a regime.


In this case, you can use Class.asSubclass:

Class<A> clazz = Class.forName("A").asSubclass(A.class);

As Tony pointed out, there are perfectly valid (and sometimes
unavoidable) constructs which will produce unchecked cast warnings.
Read up on the @SuppressWarnings annotation, and note that Sun's
compiler didn't support it until 1.5.0_06.

I'm assuming that the code you posted is a contrived example. If not,
Roedy's comment is right on; there's no reason to use Class.forName for
a known type.

HTH

--
================================================== ======================
Ian Pilcher
================================================== ======================
  Reply With Quote
Old 02-01-2006, 06:56 AM   #6
Jacob
 
Posts: n/a
Default Re: Generics and forName()

Jacob wrote:
> If I have this class:
>
> class A {
> public A(String a);
> }


As pointed out, a better example should be

class A implements B {
public A(String a);
}

Class<A> clazz = (Class<A>) Class.forName("A");
Constructor<A> ctor = clazz.getConstructor(String.class);
B b = ctor.newInstance("hello world");


Though I may understand *why* the compiler complains, I
have a feeling that a warning from the compiler is a strong
hint to modify the code so that the warning disappears.
What use has a warning if it is always there? But I guess
it boils down to the definition of the term "warning", and I
might be influenced by past (and present) experience with
C/C++ compilers as Chris suggests.

But my second question was not adressed. Why doesn't the
compiler complain in this case:

class A implements B {
public A();
}

Class<?> clazz = Class.forName("A");
B b = (B) clazz.newInstance(); // Why is this safe?


Thanks!
  Reply With Quote
Old 02-01-2006, 10:06 AM   #7
Chris Uppal
 
Posts: n/a
Default Re: Generics and forName()

Jacob wrote:

> But my second question was not adressed. Why doesn't the
> compiler complain in this case:
>
> class A implements B {
> public A();
> }
>
> Class<?> clazz = Class.forName("A");
> B b = (B) clazz.newInstance(); // Why is this safe?


It seems to be because the compiler doesn't warn (or doesn't warn as often ?)
about casts to interfaces. When you are casting the result of Class.forName()
you are casting to a concrete type, and the compiler whinges about it. It
seems to think that mistakes are less likely with casts to interfaces (why ??).
For instance the following compiles without complaint:

Object o = new A("hello")
B b = (B) o;

Kind of arbitrary... (Which rather nicely illustrates my earlier point

-- chris



  Reply With Quote
Old 02-01-2006, 10:46 AM   #8
Thomas Hawtin
 
Posts: n/a
Default Re: Generics and forName()

Chris Uppal wrote:
> Jacob wrote:
>
>> class A implements B {


>> B b = (B) clazz.newInstance(); // Why is this safe?

>
> It seems to be because the compiler doesn't warn (or doesn't warn as often ?)
> about casts to interfaces. When you are casting the result of Class.forName()
> you are casting to a concrete type, and the compiler whinges about it. It
> seems to think that mistakes are less likely with casts to interfaces (why ??).


I don't think it makes any difference whether the type is a class or an
interface.

> For instance the following compiles without complaint:
>
> Object o = new A("hello")
> B b = (B) o;


In that case, and the case above, you are casting to a type that can be
checked at runtime.

If you cast to a generic parameter type or a generic type then the cast
cannot be checked at runtime, hence the unchecked cast warning.

Some of the java.util code not only uses code that causes unchecked cast
warnings, but really allows a generic parameter type reference to point
to an incorrect type of object.

Tom Hawtin
--
Unemployed English Java programmer
http://jroller.com/page/tackline/
  Reply With Quote
Old 02-01-2006, 11:34 AM   #9
Chris Uppal
 
Posts: n/a
Default Re: Generics and forName()

Thomas Hawtin wrote:

> > For instance the following compiles without complaint:
> >
> > Object o = new A("hello")
> > B b = (B) o;

>
> In that case, and the case above, you are casting to a type that can be
> checked at runtime.


No I'm not; 'o' is of declared type Object.

-- chris




  Reply With Quote
Old 02-01-2006, 12:00 PM   #10
Chris Uppal
 
Posts: n/a
Default Re: Generics and forName()

I wrote:
> Thomas Hawtin wrote:
>
> > > For instance the following compiles without complaint:
> > >
> > > Object o = new A("hello")
> > > B b = (B) o;

> >
> > In that case, and the case above, you are casting to a type that can be
> > checked at runtime.

>
> No I'm not; 'o' is of declared type Object.


Sorry, I misread you; you said "runtime", not "compile time".

With that correction, I take your point.

I had not, in fact, realised that the compiler doesn't warn about
List<Object> list = ...
A a = (A)list.get(0);

Even more reason to avoid generics

-- chris




  Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump