Automatic conversion of numeric objects to their natives - java

I'm trying to make a function that will invoke the constructor of a class given a set of arguments
package testytest;
import java.lang.reflect.Constructor;
public class MainClass {
public static <T> T newClass(Class<?> inst, Object ... args){
#SuppressWarnings("unchecked")
Constructor<?> [] ctor = (inst.getDeclaredConstructors());
int argIndex = 0;
ctorLoop: for(Constructor<?> x : ctor){
argIndex = 0;
for(Class<?> s : x.getParameterTypes()){
if(argIndex > args.length || args[argIndex++].getClass() != s){
if(argIndex <= args.length)
System.out.println("Param doesnt match : " + args[argIndex-1].getClass() + " with " + s);
continue ctorLoop;
}
}
try{
return (T)x.newInstance(args);
}catch(Exception e){
System.err.println("Error in instantiating instance of class : " + inst);
return null;
}
}
System.err.println("No instance of constructor found for class " + inst);
return null;
}
public static void main(String[] args) {
System.out.println(newClass(Double.class,5.0));
}
}
which gives me the error
Param doesnt match : class java.lang.Double with double
Param doesnt match : class java.lang.Double with class java.lang.String
No instance of constructor found for class class java.lang.Double
looking at the line
Param doesnt match : class java.lang.Double with double
is there a way to natively make this boolean match without case swapping every native type (double,float,long,int,etc?)

There are constants defined in the wrapper classes that represent the Class objects for the primitive types. For double, use Double.TYPE.
The Class instance representing the primitive type double.
That should match the presumed double argument for the constructor you're looking for.
Other examples for other primitives are Integer.TYPE, Float.TYPE, Short.TYPE, Byte.TYPE, Long.TYPE, Character.TYPE, and Boolean.TYPE. There is even Void.TYPE for void.

No, there isn't. Both the reference type java.lang.Double and the primitive type double have corresponding Class objects. There is no way to go from one Class object to another (boxing/unboxing).
You'll have to keep your own (bi)map.

The easy way to do this is with java.beans.Statement. It handles all this conversion for you automatically.

Related

Create object using Java reflection

I receive from an external source strings that are pretty much the signature of the constructor of the object. They contain the class name and the parameters.
For example:
public class Foo {
public Foo(int x, int y, int z) {
// do something
}
}
public class Bar {
public Bar (int x, boolean bool) {
// do something
}
}
Let's say I have many classes like this, and I want to create object from these classes based on the string I receive (that contains the class name and the paramters). Can this be done?
I know I can get the class using something like this:
String className = "myClass";
Class<?> myClass = Class.forName(className);
//Constructor<?> ctor = myClass.getConstructor();
//Object object = ctor.newInstance(new Object[] { ctorArgument });
But how can I instantiate the object if I don't know at compile time how many paramters the constructor will have and of which type they will be? By the way, the classes from which I want to create the object will most likely have only one constructor available. But each class might have a different constructor compared to the other.
No problem because the newInstance() method receives an array:
public T newInstance(Object ... initargs)
So you just initialize an array containing all the arguments and pass it
something like this:
String[] argsAsString = readValuesFromString(data);
Object[] args = new Object[argAsString.length()];
int i = 0;
Class<?>[] paramTypes = ctor.getParameterTypes();
for (String argStr: argsAsString) {
args[i] = convertStringToActualType(argStr, paramTypes[i]);
i++;
}
ctor.newInstance(args);
You probably need to call getConstructors() on the class and then try to find the constructor with the correct number of arguments. This will work only if you dont have two or more constructors with the same number of arguments.
Then the convertStringToActualType() should know how to convert the string value to the actual parameter.. for example if it's boolean field `Boolean.valueOf(argStr)' etc - example:
Object convertStringToActualType(String arg, Class<?> type) {
if (type == String.class)
return arg;
if (type == Boolean.class)
return Boolean.valueOf(arg);
throw new IllegalArgumentException("type " + type.getSimpleName() + " not supported");
}

Determining a 'type' in Java

Im new to Java, is there a method in Java that tells you the type of an Object?
For example in Python if you type
type(34) it would return int
type('abc') would return string
I've been looking everywhere but I can't find a way of doing it. Any help?
Thanks a lot.
The instanceof operator is the handiest way to do runtime type checking:
if (someObject instanceof String) {
// It's a string
}
Alternately, on any instance, you can use getClass, which gives you the Class instance for the type of the object.
Class c = someObject.getClass();
The Class instance will have a getName method you can call to get a string version of the name (and lots of other handy methods).
You can get a Class object from a type name using .class, e.g.:
Class stringClass = String.class;
As Peter Lawrey points out in the comments, all of these assume you're dealing with an object reference, not a primitive. There's no way to do a runtime type check on a primitive, but that's okay, because unlike with object references (where your compile-time declaration may be Object), you always know what your primitive types are because of the declaration. It's only object types where this really comes up.
If you find yourself doing a lot of explicit type checks in your Java code, that can indicate structure/design issues. For the most part, you shouldn't need to check type at runtime. (There are, of course, exceptions.)
Basically we can achieve our goal by using the method overriding
class GetType {
void printType(byte x) {
System.out.println(x + " is an byte");
}
void printType(int x) {
System.out.println(x + " is an int");
}
void printType(float x) {
System.out.println(x + " is an float");
}
void printType(double x) {
System.out.println(x + " is an double");
}
void printType(char x) {
System.out.println(x + " is an char");
}
}
public static void main(String args[]) {
double doubleVar = 1.5;
int intVar = 7;
float floatVar = 1f;
GetType objType = new GetType();
objType.printType(doubleVar);
objType.printType(intVar);
objType.printType(floatVar);
}

binding to the right constructor at runtime - Java

I came up with a solution today involving creating classes at runtime, after parsing a file, using the Reflection API in Java.
while ((line = textReader.readLine()) != null)
{
Pattern p = Pattern
.compile("([^:]+):([^:]+)::([\\d]+)::([^:]+)::(.+)");
Matcher m = p.matcher(line);
if (m.find())
{
String id = m.group(1);
String className = m.group(2);
int orderOfExecution = Integer.valueOf(m.group(3));
String methodNameOrNew = m.group(4);
Object[] arguments = m.group(5).split("::");
if (methodNameOrNew.compareTo("new") == 0)
{
System.out.println("Loading class: " + className);
if (className.contains("Competition"))
{
continue;
}
else if (className.contains("$"))
{
continue;
}
else
{
Class<?> cl = Class.forName(className);
printMembers(cl.getConstructors(), "Constructor");
Constructor<?>[] cons = cl.getConstructors();
Object obj = cons[0].newInstance(arguments);
this.map.put(id, obj);
}
}
}
}
and printMembers():
private static void printMembers(Member[] mbrs, String s)
{
out.format("%s:%n", s);
for (Member mbr : mbrs)
{
if (mbr instanceof Field)
out.format(" %s%n", ((Field) mbr).toGenericString());
else if (mbr instanceof Constructor)
out.format(" %s%n", ((Constructor) mbr).toGenericString());
else if (mbr instanceof Method)
out.format(" %s%n", ((Method) mbr).toGenericString());
}
if (mbrs.length == 0)
out.format(" -- No %s --%n", s);
out.format("%n");
}
However, I get the following error:
Loading class: org.powertac.common.TariffSpecification
Constructor:
public org.powertac.common.TariffSpecification(org.powertac.common.Broker,org.powertac.common.enumerations.PowerType)
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at Parser.parse(Parser.java:64)
at Parser.main(Parser.java:137)
arguments[] is : 1 : CONSUMPTION. How could I create the right constructor, and give it the right arguments (types) ?
For example, in the sample parser I'm using I have:
2233:org.powertac.common.Tariff::6::new::6
then I have to create a class of the type org.powertac.common.Tariff (new tells me a new object needs to be created, and it takes a double rate as argument, in this case 6. However, I don't know it takes a double, only the argument is String (6). How could I create / convert / cast to the correct type and then assign it to the constructor? My first thought was to create a symbol table, but I'm wondering about an easier solution...
You need to use Class.getConstructor(Class...) to choose the constructor that is appropriate for arguments you wish to pass in to Constructor.newInstance(Object...)
In your example I'm going to assume an array of 1 : CONSUMPTION means you have an array equivalent to
Object[] arguments = new Object[]{Integer.valueOf(1), "CONSUMPTION"};
So you call the following
Class clazz = ... //Whatever class reference you have
Constructor c = clazz.getConstructor(Integer.class, String.class);
Object obj = c.newInstance(arguments);
If you don't know the types of your arguments you will have to test the argument set against the Class array returned by Constructor.getParameterTypes() for each constructor returned by Class.getConstructors() until you find a constructor that matches your argument array. More specifically, the array of arguments and array of classes are the same length and each class in the class array passes Class.isAssignableFrom(Class) for the class of the value in the same position in the argument array.
Implementation of above in code
public boolean canConstruct(Object[] args, Constructor<?> c){
Class<?>[] paramTypes = c.getParameterTypes();
if(args.length != paramTypes.length){
return false;
}
int i = 0;
for(Object arg: args){
if(!paramTypes[i].isAssignableFrom(arg.getClass())){
return false;
}
i++;
}
return true;
}
In order to use this you will have to have your argument array as you want to pass it to the constructor. You could try to edit your input so that it includes type information (this is similar to how java serialization works) so that you can construct the arguments for the constructor argument array via reflection with their own type constructors

Generic Casting on primitive value causing ClassCastException

I have a method below doing casting on a String according to the given type, assuming the String given must be correct.
private static <T> T parsePrimitive(final Class<T> primitiveType, final String primitiveValue) {
if (primitiveType.equals(int.class) || primitiveType.equals(Integer.class)) {
return primitiveType.cast(Integer.parseInt(primitiveValue));
}
/*
...
for the rest of the primitive type
...
*/
}
However, when I call parsePrimitive(int.class, "10");,
primitiveType.cast(Integer.parseInt(primitiveValue));
This causes ClassCastException, any idea for this?
p.s. In fact, when I use Object as the return type, and no casting in before return, it works fine outside the method, but this is not generic enough I think.
Thanks in advance for any help.
You are mixing up autoboxing and casting. The java compiler will generate bytecode to box and unbox your primitives to objects and vice versa, but the same does not apply to types.
Boxing/Unboxing = variables
Casting = types
In your particular case, int.class and Integer.class are not assignable from each other.
Class<?> intClazz = int.class;
Class<?> integerClazz = Integer.class;
System.out.println(intClazz);
System.out.println(integerClazz);
System.out.println(integerClazz.isAssignableFrom(intClazz));
Output:
int
class java.lang.Integer
false
With the amount of specialized checks you would have to put in your logic I am not sure its worth trying to come up with a generic method for parsing a String into a primitive value.
int.class is a VM internal class and not the same thing as Integer.class. Here's a small snippet of code to show the differences between int.class and Integer.class.
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
dump(int.class);
System.out.println("---");
dump(Integer.class);
}
private static void dump(Class<?> c) {
System.out.printf(
"Name: %s%n" +
"Superclass: %s%n" +
"Interfaces: %s%n" +
"Modifiers: %s%n",
c.getName(),
c.getSuperclass() == null ? "null" : c.getSuperclass().getName(),
Arrays.asList(c.getInterfaces()),
Modifier.toString(c.getModifiers()));
}
}
Outputs:
Name: int
Superclass: null
Interfaces: []
Modifiers: public abstract final
---
Name: java.lang.Integer
Superclass: java.lang.Number
Interfaces: [interface java.lang.Comparable]
Modifiers: public final

How to test whether method return type matches List<String>

What is the easiest way to test (using reflection), whether given method (i.e. java.lang.Method instance) has a return type, which can be safely casted to List<String>?
Consider this snippet:
public static class StringList extends ArrayList<String> {}
public List<String> method1();
public ArrayList<String> method2();
public StringList method3();
All methods 1, 2, 3 fulfill the requirement. It's quite easy to test it for the method1 (via getGenericReturnType(), which returns instance of ParameterizedType), but for methods2 and 3, it's not so obvious. I imagine, that by traversing all getGenericSuperclass() and getGenericInterfaces(), we can get quite close, but I don't see, how to match the TypeVariable in List<E> (which occurs somewhere in the superclass interfaces) with the actual type parameter (i.e. where this E is matched to String).
Or maybe is there a completely different (easier) way, which I overlook?
EDIT: For those looking into it, here is method4, which also fulfills the requirement and which shows some more cases, which have to be investigated:
public interface Parametrized<T extends StringList> {
T method4();
}
I tried this code and it returns the actual generic type class so it seems the type info can be retrieved. However this only works for method 1 and 2. Method 3 does not seem to return a list typed String as the poster assumes and therefore fails.
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try{
Method m = Main.class.getDeclaredMethod("method1", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method2", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method3", new Class[]{});
instanceOf(m, List.class, String.class);
m = Main.class.getDeclaredMethod("method4", new Class[]{});
instanceOf(m, StringList.class);
}catch(Exception e){
System.err.println(e.toString());
}
}
public static boolean instanceOf (
Method m,
Class<?> returnedBaseClass,
Class<?> ... genericParameters) {
System.out.println("Testing method: " + m.getDeclaringClass().getName()+"."+ m.getName());
boolean instanceOf = false;
instanceOf = returnedBaseClass.isAssignableFrom(m.getReturnType());
System.out.println("\tReturn type test succesfull: " + instanceOf + " (expected '"+returnedBaseClass.getName()+"' found '"+m.getReturnType().getName()+"')");
System.out.print("\tNumber of generic parameters matches: ");
Type t = m.getGenericReturnType();
if(t instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType)t;
Type[] actualGenericParameters = pt.getActualTypeArguments();
instanceOf = instanceOf
&& actualGenericParameters.length == genericParameters.length;
System.out.println("" + instanceOf + " (expected "+ genericParameters.length +", found " + actualGenericParameters.length+")");
for (int i = 0; instanceOf && i < genericParameters.length; i++) {
if (actualGenericParameters[i] instanceof Class) {
instanceOf = instanceOf
&& genericParameters[i].isAssignableFrom(
(Class) actualGenericParameters[i]);
System.out.println("\tGeneric parameter no. " + (i+1) + " matches: " + instanceOf + " (expected '"+genericParameters[i].getName()+"' found '"+((Class) actualGenericParameters[i]).getName()+"')");
} else {
instanceOf = false;
System.out.println("\tFailure generic parameter is not a class");
}
}
} else {
System.out.println("" + true + " 0 parameters");
}
return instanceOf;
}
public List<String> method1() {
return null;
}
public ArrayList<String> method2() {
return new ArrayList<String>();
}
public StringList method3() {
return null;
}
public <T extends StringList> T method4() {
return null;
}
This outputs:
Testing method: javaapplication2.Main.method1
Return type test succesfull: true (expected 'java.util.List' found 'java.util.List')
Number of generic parameters matches: true (expected 1, found 1)
Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String')
Testing method: javaapplication2.Main.method2
Return type test succesfull: true (expected 'java.util.List' found 'java.util.ArrayList')
Number of generic parameters matches: true (expected 1, found 1)
Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String')
Testing method: javaapplication2.Main.method3
Return type test succesfull: false (expected 'java.util.List' found 'com.sun.org.apache.xerces.internal.xs.StringList')
Number of generic parameters matches: true 0 parameters
Testing method: javaapplication2.Main.method4
Return type test succesfull: true (expected 'com.sun.org.apache.xerces.internal.xs.StringList' found 'com.sun.org.apache.xerces.internal.xs.StringList')
Number of generic parameters matches: true 0 parameters
Solving this in general is really not easy to do yourself using only the tools provided by Java itself. There are a lot of special cases (nested classes, type parameter bounds,...) to take care of.
That's why I wrote a library to make generic type reflection easier: gentyref. I added sample code (in the form of a JUnit test) to show how to use it to solve this problem: StackoverflowQ182872Test.java. Basically, you just call GenericTypeReflector.isSuperType using a TypeToken (idea from Neil Gafter) to see if List<String> is a supertype of the return type.
I also added a 5th test case, to show that an extra transformation on the return type (GenericTypeReflector.getExactReturnType) to replace type parameters with their values is sometimes needed.
This thread on the java.net forums might be helpful (although I have to admit I didn't understand everything they said).
I think you are already on the right track. Just keep using getGenericSuperclass() and getGenericInterface() until you start getting parameterized types back...
So basically:
//For string list
ParameterizedType type = (ParameterizedType)StringList.class.getGenericSuperclass();
System.out.println( type.getActualTypeArguments()[0] );
//for a descendant of string list
Class clazz = (Class)StringListChild.class.getGenericSuperclass();
ParameterizedType type = (ParameterizedType)clazz.getGenericSuperclass();
System.out.println( type.getActualTypeArguments()[0] );
You'd want to build something that was recursive that would check for this--maybe even go up the chain looking for java.util.List.

Categories