how to get the class of generic? - java

I'm reading the source code about spring, and want to know the class of return value that is generic, What should I do?
public static <T> T getBean(String name) {
assertContextInjected();
System.out.println();
return (T) applicationContext.getBean(name);
}

Unfortunately, in Java the short answer is that you can't. You can consider Generics as basically just a compile-time feature to ensure correct handling. However, the compiled bytecode discards all the type information in a process called "Type Erasure", so effectively what the JVM gets at runtime is simply :
public static Object getBean(String name) {
However, none of that is the root cause of your problem, which is to do with your call. I assume you have something like :
SomeClass someVariable = getBean("someName");
What's happening is that the bean that you have requested is not of type SomeClass (and casting is not going to help you with that) - So what you need to do is figure out what class the bean is that Spring is giving you, and then change the "SomeClass" in the caller to expect that type.

Related

How to avoid type safety warning with generic interfaces and Class.forName

I have the following code which is forking fine:
private <X extends SomeInterface<MyImplementation>> void test(String fqcn)
{
Class<X> c = (Class<X>)Class.forName(fqcn).asSubclass(SomeInterface.class);
...
}
However, I get a type safety warning
Type safety: Unchecked cast from Class<capture#2-of ? extends SomeInterface> to Class<X>
and wondering how to fix it?
There is no way to prove that this casting is safe and would succeed. You're performing casting of Class<?> (of unknown type) returned by Class.forName() into the Class<X> (of something), the compiler can't verify if what you're doing is correct.
The only thing you can do is to suppress the warning by placing annotation #SuppressWarnings("unchecked") on the method on the problematic statement:
#SuppressWarnings("unchecked")
private <X extends SomeInterface<MyImplementation>> void test(String fqcn) {
Class<X> c = (Class<X>)Class.forName(fqcn).asSubclass(SomeInterface.class);
...
}
Or
private <X extends SomeInterface<MyImplementation>> void test(String fqcn) {
#SuppressWarnings("unchecked")
Class<X> c = (Class<X>)Class.forName(fqcn).asSubclass(SomeInterface.class);
...
}
Read the reflection java.lang.Class "api docs" for forName method, it should be wrapped in java.lang.ClassNotFoundException and java.lang.ClassCastException.
The correct Exception(s) should remove that warning.
use isInstance(theCreatedClassReference) from java.lang.Class
don't want to try without code and compiler , take too long for me.
isInstance() returns a boolean and is the correct to use for Class.forName(stringnametoload) check alike the instanceof operator
when creating a Class check its constructed reference in an if test
the multi argument Class.forName allows class loading usage designation of whether it is "initialized".
sorry about the botched code attempt.
If you are actually making a usable reference then maybe check with instanceof but the actions DO require the exception wrappers (not a bad idea when they can be interfaces and other types in one).
I can only presume from your code you are loading a class that will be returned "something like (and as the byte code compiler sees it)" a <T> type by genericsthat could be any type, so the runtime would have no idea what resource of byte code would be loaded.
Not knowing what the T type will be is extremely dangerous.
If you flag Class.forName with initialize false using its multi argument method version you can load an uninstantiated class as a test to see that the dynamic resource is true for the compiled code before it is able to be loaded live.
It would then tested the resource class loaded.

Can't register JDBC driver

I am writing an application using java JDBC that queries and inserts data into an Oracle database.
I'm using the SimpleDriverDataSource from springframework API to implement the standard JDBC DataSource Inteface.
here is part of my code
dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(Class.forName(credentials.getDriverClass()));
I'm trying to keep the code independent of DriverClass used, and I know that class.forName() returns a class object for the class string name.
The problem is that I'm getting a compilation error saying:
the method setDriverClass(Class<? extends Driver>) in the type SimpleDriverDataSource is not applicable for the arguments (Class<capture#1-of ?>
I don't really understand what these symbols mean, or what is causing the error?
The SimpleDriverDataSource#setDriverClass(Class) is implemented as
public void setDriverClass(Class<? extends Driver> driverClass) {
this.driver = BeanUtils.instantiateClass(driverClass);
}
So it is expecting a Class object of a type that is a subtype of Driver.
The Class.forName(String) method is implemented as
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
In other words it returns a Class<?> object, ie. a Class object of any type, not necessarily one that is a subtype of Driver. Therefore the declared type of the returned object is not a valid argument to the setDriverClass() method.
One solution is to instantiate your Driver class yourself and use the setDriver(Driver) method instead
Class<?> clazz = Class.forName(credentials.getDriverClass());
Object driver = BeanUtils.instantiateClass(clazz);
dataSource.setDriver((Driver) driver);
Note that the above will throw a ClassCastException at runtime if the class you try to instantiate is not a subtype of Driver.
Alternatively, as suggested by BalusC you can cast the value returned by Class.forName()
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass((Class<Driver>)Class.forName("com.mysql.jdbc.Driver"));
Adding some #SuppressWarnings if you don't like IDE warnings.
This is a little trick for Java Generics that's worth knowing.
The problem happens when you are dealing with type parameters that you
know are consistent, but which are not explicit in your code. This is
common if you are processing a not-completely-typed collection.
To make things clearer, I'll use the following example: Consider a system
that transfers various values from one place to another (perhaps it is a
scheduler sending messages of different types within a system).
We might have an interface that can both provide and receive certain
message types:
public interface Connection<Type>
{
Type read();
void write(Type value);
}
And our scheduler might look something like this:
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
for (Connection<?> cns: cnxs) {
cnx.write(cnx.read);
}
}
}
(Note that is shorthand for and we use it here
because the cnxs collection contains a Connections with a variety of
different type parameters).
Unfortunately that won't compile! The error given be Eclipse with Java
1.6 is "The method write(capture#2-of ?) in the type
Connection is not applicable for the arguments
(capture#3-of ?)".
The reason this won't compile is that the type parameter for the value
being returned by the Connection and the type parameter for the value it
will receive are being treated separately. Each is being treated as
"capture-of ?" which means "some subclass of Object". And the compiler is
then (understandably) saying "I can't send 'subclass X of Object' to a
method that expects 'subclass Y of Object' because I don't know if they
are the same subclass".
To make this work we need to introduce the common type parameter
explicitly. Unfortunately the following code, or something like it,
doesn't work (as far as I can tell). There is no way to introduce a type
parameter in the middle of a block of code (what we really want here is
better support for polymorphism):
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
// syntax error!
for (<E> Connection<E> cns: cnxs) {
E value = cnx.read();
cnx.write(value);
}
}
}
But what we can do is add a helper method that introduces a new type
parameter:
class Scheduler
{
public void process(Collection<Connection<?>> cnxs)
{
for (Connection<?> cnx: cnxs) {
helper(cnx);
}
}
private <E> void helper(Connection<E> cnx)
{
E value = cnx.read();
cnx.write(value);
}
}
This does what we want! The code validates, compiles, and runs.
In summary then: Sometimes you can "lose" an explicit generic type
parameter (often because you are dealing with a collection of different
types). You can re-introduce that type parameter by adding an extra
helper method.

Guice generics - how can I make it less ugly?

I have an interface Producer<T> and a concrete FooProducer that implements Producer<Foo>. Binding this in guice looks ugly as sin:
bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);
I have lots of these such bindings. I have tried the following:
static <T> TypeLiteral<Producer<T>> producer() {
return new TypeLiteral<Producer<T>>(){};
}
With calls made in this way:
bind(ContainingClass.<Foo>producer()).to(FooProducer.class);
But it gives an error along the lines of Producer<T> is not specific enough....
Am I going about this in the wrong way?
Instead of
bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);
try a convenience method like
static <T> Key<Producer<T>> producerOf(Class<T> type) {
return (Key<Producer<T>>)Key.get(Types.newParameterizedType(Producer.class,type));
}
and then in your module
bind(producerOf(Foo.class)).to(FooProducer.class);
That unchecked cast should be safe. Key is com.google.inject.Key and Types is com.google.inject.util.Types.
good luck
You can save 8 characters by typing new Key<Producer<Foo>>(){} rather than new TypeLiteral<Producer<Foo>>(){}. Or by using the equivalent #Provides method:
#Provides
public Producer<Foo> provideFooProducer(FooProducer fooProducer) {
return fooProducer;
}
I believe that due to how TypeLiterals work, you have to actually write new TypeLiteral<Producer<Foo>>(){} or the necessary type information will not be available. They utilize the fact that a class that has fully specified its generic types can have information on those types retrieved. When you write new TypeLiteral<Producer<T>>(){}, you aren't specifying what T is, so that information isn't available.
It's subjective, but I don't think creating a type literal looks too ugly, considering what it does.
As an aside, I don't know what your Producer interface does, but if it is just used for producing instances of T (with a method that takes no arguments), you could use Guice's Provider interface instead. Then you just have to do:
bind(Foo.class).toProvider(FooProvider.class);
And you can inject a Foo or a Provider<Foo> anywhere.

Javac flags and Eclipse settings to process Class.<GenericType>method() invocations

It happens to see
Collections.<Object>asList(...)
method invocations in the code, but Eclipse seems do not understand this(with my configuration) and shows this as compilation error.
Is my Eclipse configuration wrong? Or this doesn't work with Sun compiler (jdk 1.6.013)? What should I check / enable for thing like this?
If Collections is meant to be java.util.Collections, then Eclipse is correct as there is no Collections.asList().
I think you meant Arrays.asList() .
In java typed methods depend on some sort of input to determine the output, so you could declare a method
public List<T> asList(T[] myArray) {
...
}
When calling that method you just pass in your class and the compiler knows what the return type is.
String[] myArray = {"asdf", "asdf"};
List<String> result = asList(myArray);
Alternatively, you could have a typed class that uses that type parameter to determine result
public class Foo<T> {
public void myMethod(T myObject) {
..do something
}
}
If you create a Foo like
Foo<String> foo = new Foo<String>();
you can only invoke myMethod with a String
foo.myMethod("asdf"); //okay
foo.myMethod(new BigInteger(1)); //not okay
There are a lot more things you can do with typed objects, but hopefully this gets to what you were asking about.

Java generics question - Class<T> vs. T?

I'm using Hibernate validator and trying to create a little util class:
public class DataRecordValidator<T> {
public void validate(Class<T> clazz, T validateMe) {
ClassValidator<T> validator = new ClassValidator<T>(clazz);
InvalidValue[] errors = validator.getInvalidValues(validateMe);
[...]
}
}
Question is, why do I need to supply the Class<T> clazz parameter when executing new ClassValidator<T>(clazz)? Why can't you specify:
T as in ClassValidator<T>(T)?
validateMe.getClass() as in ClassValidator<T>(validateMe.getClass())
I get errors when I try to do both options.
Edit: I understand why #1 doesn't work. But I don't get why #2 doesn't work. I currently get this error with #2:
cannot find symbol
symbol : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>)
location: class org.hibernate.validator.ClassValidator<T>
Note: Hibernate API method is (here)
Because T is not a value - it's just a hint for the compiler. The JVM has no clue of the T. You can use generics only as a type for the purposes of type checking at compile time.
If the validate method is yours, then you can safely skip the Class atribute.
public void validate(T validateMe) {
ClassValidator<T> validator =
new ClassValidator<T>((Class<T>) validateMe.getClass());
...
}
But the ClassValidator constructor requires a Class argument.
Using an unsafe cast is not preferred, but in this case it is actually safe if you don't have something like this:
class A {..}
class B extends A {..}
new DataRecordValidator<A>.validate(new B());
If you think you will need to do something like that, include the Class argument in the method. Otherwise you may be getting ClassCastException at runtime, but this is easily debuggable, although it's not quite the idea behind generics.
Because ClassValidator is requiring a Class object as its parameter, NOT an instance of the class in question. Bear in mind you might be able to do what you're trying to do with this code:
ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass());

Categories

Resources