Create object using Java reflection - java

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");
}

Related

Is there a way to create a variable that matches T argument in a generic class?

I have a generic class, let's call it Parser<T>. In the main program, I would like to create an instance of Parser where T depends on the input parameters (because there would be a lot of options).
For instance, I have a variable Class x = BigInteger.class. So that means that I want T to be BigInteger.
Is there a possible way to use my variable instead of T to get Parser<BigInteger>? If not how would you recommend to do it?
P.S. I'm new to Java and also not a native English speaker, so I understand that the question may be very silly or has already been answered, if that's the case, I'm sorry.
There is no good way to do that. Explicit or inferred type parameters have to static (compile time) types.
By the sounds of it, you may be better off with a non-generic type that takes a Class as a parameter.
If you stick with generics you will probably end up with something ugly, like this:
if (class.getName().equals("java.lang.BigInteger")) {
BigInteger i = new Parser<BigInteger>().parse(someString);
// do something with 'i'
} else if (...) {
// ad nauseum
}
It is also possible that you would be better off with the type parameter on the parse method rather than the class; e.g.
class Parser {
<T> parse(Class<T> expected, String input) {
// do parsing of input
if (expected.isInstance(result)) {
return expected.cast(result) {
} else {
// throw some exception
}
}
But even then, the caller needs a separate static call for each case if it is going to make use of the return type; e.g.
if (class.getName().equals("java.lang.BigInteger")) {
BigInteger i = parser.parse(BigInteger.class, someString);
// do something with 'i'
} else if (...) {
// ad nauseum
}
You should pass your variable to the constructor.
public class Parser<T> {
final Class<T> clazz;
public Parser(Class<T> clazz) {
this.clazz = clazz;
}
#Override
public String toString() {
return "Parser<" + clazz.getSimpleName() + ">";
}
}
and
Class a = BigInteger.class;
Parser parser1 = new Parser(a);
System.out.println(parser1);
Class b = String.class;
Parser parser2 = new Parser(b);
System.out.println(parser2);
->
Parser<BigInteger>
Parser<String>

find class of array (String[].class --> String.class) [duplicate]

Object o = new Long[0]
System.out.println( o.getClass().isArray() )
System.out.println( o.getClass().getName() )
Class ofArray = ???
Running the first 3 lines emits;
true
[Ljava.lang.Long;
How do I get ??? to be type long? I could parse the string and do a Class.forname(), but thats grotty. What's the easy way?
Just write
Class ofArray = o.getClass().getComponentType();
From the JavaDoc:
public Class<?> getComponentType()
Returns the Class representing the component type of an array. If this class does not represent an array class this method returns null.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getComponentType():
public Class<?> getComponentType()
Returns the Class representing the component type of an array. If this class does not represent an array class this method returns null...
#ddimitrov is the correct answer. Put into code it looks like this:
public <T> Class<T> testArray(T[] array) {
return array.getClass().getComponentType();
}
Even more generally, we can test first to see if the type represents an array, and then get its component:
Object maybeArray = ...
Class<?> clazz = maybeArray.getClass();
if (clazz.isArray()) {
System.out.printf("Array of type %s", clazz.getComponentType());
} else {
System.out.println("Not an array");
}
A specific example would be applying this method to an array for which the component type is already known:
String[] arr = {"Daniel", "Chris", "Joseph"};
arr.getClass().getComponentType(); // => java.lang.String
Pretty straightforward!

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

How to get parameter types using reflection?

I want to use functions having different numbers of parameters. The problem is that I don't know the number of parameters of each function, and also I don't know names of function as they are stored in an array. I only knows the class name, but don't want to use getDeclaredMethods as it will increase search time. Is there a way to get the parameter types for each function?
What I usually do when I have to look up methods is to generate a cache key from the query I am doing and save the search result with this cache key in a map.
Example:
I know the method parameters are Boolean.TRUE, Arrays.asList("foo","bar","baz") and BigInteger.valueOf(77777l)
My class contains a method with the signature
public foo(boolean, Collection, Number)
There's no way I can directly map the parameters to the parameter types because I just don't know which of the super classes or interfaces is the parameter type as you can see from the following table:
Expected Type | What I have
-----------------------------------------------------
boolean | java.lang.Boolean
java.util.Collection | java.util.Arrays$ArrayList
java.lang.Number | java.math.BigInteger
Each of these pairs is compatible, but there's no way to find the compatible method without defining a comparison method, something like this:
// determine whether a method's parameter types are compatible
// with my arg array
public static boolean isCompatible(final Method method,
final Object[] params) throws Exception{
final Class<?>[] parameterTypes = method.getParameterTypes();
if(params.length != parameterTypes.length){
return false;
}
for(int i = 0; i < params.length; i++){
final Object object = params[i];
final Class<?> paramType = parameterTypes[i];
if(!isCompatible(object, paramType)){
return false;
}
}
return true;
}
// determine whether a single object is compatible with
// a single parameter type
// careful: the object may be null
private static boolean isCompatible(final Object object,
final Class<?> paramType) throws Exception{
if(object == null){
// primitive parameters are the only parameters
// that can't handle a null object
return !paramType.isPrimitive();
}
// handles same type, super types and implemented interfaces
if(paramType.isInstance(object)){
return true;
}
// special case: the arg may be the Object wrapper for the
// primitive parameter type
if(paramType.isPrimitive()){
return isWrapperTypeOf(object.getClass(), paramType);
}
return false;
}
/*
awful hack, can be made much more elegant using Guava:
return Primitives.unwrap(candidate).equals(primitiveType);
*/
private static boolean isWrapperTypeOf(final Class<?> candidate,
final Class<?> primitiveType) throws Exception{
try{
return !candidate.isPrimitive()
&& candidate
.getDeclaredField("TYPE")
.get(null)
.equals(primitiveType);
} catch(final NoSuchFieldException e){
return false;
} catch(final Exception e){
throw e;
}
}
So what I'd do is have a method cache:
private static final Map<String, Set<Method>> methodCache;
and add a lookup method like this:
public static Set<Method> getMatchingMethods(final Class<?> clazz,
final Object[] args) throws Exception{
final String cacheKey = toCacheKey(clazz, args);
Set<Method> methods = methodCache.get(cacheKey);
if(methods == null){
final Set<Method> tmpMethods = new HashSet<Method>();
for(final Method candidate : clazz.getDeclaredMethods()){
if(isCompatible(candidate, args)){
tmpMethods.add(candidate);
}
}
methods = Collections.unmodifiableSet(tmpMethods);
methodCache.put(cacheKey, methods);
}
return methods;
}
private static String toCacheKey(final Class<?> clazz, final Object[] args){
final StringBuilder sb = new StringBuilder(clazz.getName());
for(final Object obj : args){
sb.append('-').append(
obj == null ? "null" : obj.getClass().getName());
}
return sb.toString();
}
That way, subsequent lookups will take much less time than the first one (for parameters of the same type).
Of course since Class.getDeclaredMethods() uses a cache internally, the question is whether my cache improves performance at all. It's basically a question of what's faster:
generating a cache key and querying a HashMap or
iterating over all methods and querying for parameter compatibility
My guess: for large classes (many methods), the first method will win, otherwise the second will

With Java reflection how to instantiate a new object, then call a method on it?

I'm pretty new to Java, and I'm facing a reflection issue.
Let's say i have to dynamically call the method fooMethod on an instance of the class Foobar
I got so far an instance of Foobar with:
Object instance = Class.forName("Foobar").newInstance();
Let's say I know there's a method fooMethod on this object (I can even check this with Class.forName("Foobar").getDeclaredMethods() ) , how to call it, please?
Method method = getClass().getDeclaredMethod("methodName");
m.invoke(obj);
This is in case the method doesn't have arguments. If it has, append the argument types as arguments to this method.
obj is the object you are calling the method on.
See the java.lang.Class docs
You can use reflection
sample class
package com.google.util;
class Maths {
public Integer doubleIt(Integer a) {
return a*2;
}
}
and use something like this-
step 1:- Load class with given input name as String
Class<?> obj = Class.forName("Complete_ClassName_including_package");
//like:- Class obj = Class.forName("com.google.util.Maths");
step 2:- get Method with given name and parameter type
Method method = obj.getMethod("NameOfMthodToInvoke", arguments);
//arguments need to be like- `java.lang.Integer.class`
//like:- Method method= obj.getMethod("doubleIt", java.lang.Integer.class);
step 3:- invoke Method by passing instance of Object and argument
Object obj2 = method.invoke(obj.newInstance(), id);
//like :- method.invoke(obj.newInstance(), 45);
YOU CAN DO STEP 2 LIKE THIS ALSO
(when you do not know particular method exists in a class you check all method by looping method's array)
Method[] methods = obj.getMethods();
Method method = null;
for(int i=0; i < methods.length(); i++) {
if(method[1].getName().equals("methodNameWeAreExpecting")) {
method = method[i];
}
}
Purely reflection: Method.invoke.
The other solution is to require the item you are reflectively creating to implement a known interface and cast to this interface and use as normal.
The latter is commonly used for "plugins", the former is not used very often.
You can start by reading about it here.
As for the code you are after it is like this (from the same resource):
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods) {
String mname = m.getName();
if (!mname.startsWith("test")
|| (m.getGenericReturnType() != boolean.class)) {
continue;
}
Type[] pType = m.getGenericParameterTypes();
if ((pType.length != 1)
|| Locale.class.isAssignableFrom(pType[0].getClass())) {
continue;
}
out.format("invoking %s()%n", mname);
try {
m.setAccessible(true);
Object o = m.invoke(t, new Locale(args[1], args[2], args[3]));
out.format("%s() returned %b%n", mname, (Boolean) o);
// Handle any exceptions thrown by method to be invoked.
} catch (InvocationTargetException x) {
Throwable cause = x.getCause();
err.format("invocation of %s failed: %s%n",
mname, cause.getMessage());
}
This should work for you:
((Foobar)instance).fooMethod()
Class.forName("Foobar").newInstance();
is now deprecated (https://docs.oracle.com/javase/9/docs/api/java/lang/Class.html#forName-java.lang.Module-java.lang.String-)
Class.forName("Foobar").getDeclaredConstructor().newInstance()
or if you need a specific constructor:
Constructor constructor = Class.forName("java.lang.String").getConstructor(String.class);
String object = (String) constructor.newInstance("Hello");

Categories