how to get the return type of a Generic method

S

Sideswipe

I have a situation where I need to get a the return type of a method
who's signature is based on a generic. Example:


public class SomeClass<T> {

public T getValue(Object whatever) {
}

}

public static void main(String[] args) {

SomeClass<String> instance = new SomeClass<String>();

Class c = instance.getClass();
Method m = c.getMethod("getValue",Object.class);
Class rt = m.getReturnType();
System.out.println(rt)

}

This results in "class java.lang.Object" as I suspected it would (I
had to try). is there a way (without adding a parameter) to determine
this?? This is legacy code and while I have access to it, I have
limited flexibility as to what i can do.

And please, no judgmental comments, only ideas.
 
A

Arne Vajhøj

Sideswipe said:
I have a situation where I need to get a the return type of a method
who's signature is based on a generic. Example:

public class SomeClass<T> {

public T getValue(Object whatever) {
}

}

public static void main(String[] args) {

SomeClass<String> instance = new SomeClass<String>();

Class c = instance.getClass();
Method m = c.getMethod("getValue",Object.class);
Class rt = m.getReturnType();
System.out.println(rt)

}

This results in "class java.lang.Object" as I suspected it would (I
had to try). is there a way (without adding a parameter) to determine
this?? This is legacy code and while I have access to it, I have
limited flexibility as to what i can do.

The information about T are not present in the byte code and
therefore reflection can not get it.

Arne
 
R

Roedy Green

This results in "class java.lang.Object" as I suspected it would (I
had to try). is there a way (without adding a parameter) to determine
this?? This is legacy code and while I have access to it, I have
limited flexibility as to what i can do.

The problem is the information does not exist at run time. Generics
are purely a compile-time type checking mechanism.

So if you want it, you will have to pass a Class object yourself.

See http://mindprod.com/jgloss/generics.html
 
M

Mark Space

Sideswipe said:
This results in "class java.lang.Object" as I suspected it would (I
had to try). is there a way (without adding a parameter) to determine
this?? This is legacy code and while I have access to it, I have
limited flexibility as to what i can do.

If it's legacy code, how did they get the run type before? I think your
best bet is to rethink the problem...

However:

public class SomeClass<T> {

public T getValue(Object whatever) {
}

}

public static void main(String[] args) {

SomeClass<String> instance = new SomeClass<String>();

// For input use whatever works...
Object obj = instance.getVale( null );
Class class = obj.getClass()
System.out.println( class.getName() );

}

If you truly don't know, this is the only way I can think of, is to
actually obtain an object, and query it's class.

If that can't work, then I think you are going to have to refactor the
code and pass a class object in as a parameter when you create the class.
 
M

Mark Space

Mark said:
If that can't work, then I think you are going to have to refactor the
code and pass a class object in as a parameter when you create the class.

This whole reifiable type issue is starting to burn me up. I think Sun
should give us a Reifiable annotation that we can use to make the
compiler add some boilerplate for reifiable types.

Here's what I mean. There's a lot of boilerplate here that could be
just generated. The only thing I'm not sure of is how to handle Classes
where the Class object refers to a reifiable type. Maybe more maybe later.

I wrote this for my own edification, not because I think the OP needs
it. Are we at the point where there should be a standard pattern for
rolling your own reifiable type? Here's a simple example I have.
Please let me know what you think.

The pattern is:

1. Curse Sun for not giving us reifiable types.

2. Add a final Class variable for each parameterized type.

3. Add a constructor so that the class can be instatiated with just it's
types.

4. Modify existing constructors so that they set the correct types for
their parameters.

5. Add getters for each reifiable type to return the class. Name these
by adding the word "Class" to the end of the method name for the getters
for the corresponding values. For example, the getter to return the
class of getSomeValue() is getSomeValueClass().

6. Optionally add a convenience method to return the class of all
parameterized type. Name this method by adding the word "Classes" to the
end of the method name (which is the same as adding the word "Classes"
to the end of the constructor. This method should return a Class array
with the elements from 0 up corresponding to the order of the arguments
in the constructor left to right.

7. Don't forget to declare the number of reifiable types as a constant.

Well that's what I got so far. I'd really rather see this integrated
into reflection rather than having to do it by hand each time. If Sun
can overload a try-catch to automagically close Closeable objects, they
can gen some boilerplate for reifiable objects.


package reifiabletypes;

import java.math.BigDecimal;

/**
* Curse you, Sun!!
* Give us @Reifiable.
*/
public class Main {

/**
* @param args the command line arguments are ignored.
*/
public static void main(String[] args) {
// TODO code application logic here
SomePair<BigDecimal,BigDecimal> spbn =
new SomePair( BigDecimal.class, BigDecimal.class );
SomePair<Integer, Integer> spii =
new SomePair( Integer.class, Integer.class );

System.out.println("spbn first class: " + spbn.getFirstClass() );
System.out.println("spbn second class: " + spbn.getSecondClass() );
System.out.println("spii first class: " + spii.getFirstClass() );
System.out.println("spii second class: " + spii.getSecondClass() );

}

}

/**
* A sample, test reifiable type.
*/

class SomePair<FIRST, SECOND>
{
public final static int NUM_PARM_TYPES = 2;

private FIRST first;
private SECOND second;
private Class<FIRST> firstClass;
private Class<SECOND> secondClass;

public SomePair(Class<FIRST> firstClass,
Class<SECOND> secondClass)
{
this.firstClass = firstClass;
this.secondClass = secondClass;
}

public SomePair(FIRST first, SECOND second )
{
this.first = first;
this.second = second;
firstClass = (Class<FIRST>)first.getClass();
secondClass = (Class<SECOND>)second.getClass();
}

public FIRST getFirst() {
return first;
}

public SECOND getSecond() {
return second;
}

public Class<FIRST> getFirstClass() {
return firstClass;
}

public Class<SECOND> getSecondClass() {
return secondClass;
}

public Class [] getSomePairClasses( ) {
Class [] ca = new Class[NUM_PARM_TYPES];
ca[0] = firstClass;
ca[1] = secondClass;
return ca;
}
}
 
S

Sideswipe

Yeah, see this is the problem. I need to know what type WOULD be
returned without actually calling the function and returning it.
Basically, the problem is that I need to find compatible Comparables
based on this method. I kinda suspected I would need a class param but
I don't want to have to do it/make that case. It would be truly great
to KNOW things about the type T

Christian
 
L

Lew

Sideswipe said:
Yeah, see this is the problem. I need to know what type WOULD be
returned without actually calling the function and returning it.
Basically, the problem is that I need to find compatible Comparables
based on this method. I kinda suspected I would need a class param but
I don't want to have to do it/make that case. It would be truly great
to KNOW things about the type T

You could start with Mark Space's suggestion and change the type bounds
somewhat. Let the compiler figure out the supertype; don't do it by hand.

<sscce>
package testit;

import java.text.DateFormat;
import java.text.SimpleDateFormat;

/** SomePair - .
*/
public class SomePair <F extends Comparable<? super S>,
S extends Comparable<? super F>>
{
private final F first;
private final S second;

public SomePair( F f, S s )
{
this.first = f;
this.second = s;
}

public final F getFirst() { return first; }
public final S getSecond() { return second; }

public int compareFirstToSecond()
{
return first.compareTo( second );
}

/** Main method.
* @param args <code>String []</code> program arguments.
*/
public static void main( String[] args )
{
Integer a = 17;
Integer b = 19;
SomePair<Integer, Integer> sp =
new SomePair<Integer, Integer>( a, b );
System.out.println( "a = " + sp.getFirst()
+ ", b = " + sp.getSecond()
+ ", compare " + sp.compareFirstToSecond() );

java.sql.Date sd = new java.sql.Date( new java.util.Date().getTime() );
try
{
Thread.sleep( 1 );
}
catch ( InterruptedException ex )
{
}
java.util.Date ud = new java.util.Date();

SomePair<java.sql.Date, java.util.Date> dp =
new SomePair<java.sql.Date, java.util.Date>( sd, ud );
show( dp );

sd = new java.sql.Date( ud.getTime() );
dp = new SomePair<java.sql.Date, java.util.Date>( sd, ud );
show( dp );
}

private static final String DFS = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
private static final DateFormat DF = new SimpleDateFormat( DFS );

private static void show( SomePair<java.sql.Date, java.util.Date> dp )
{
System.out.print( "java.sql.Date " );
System.out.print( DF.format( dp.getFirst() ));
System.out.print( ", java.util.Date " );
System.out.print( DF.format( dp.getSecond() ));
System.out.print( ", compare " );
System.out.println( dp.compareFirstToSecond() );
}
}
</sscce>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top