for example, i have 10 classes created with some methods in it. now, i want to create a method which takes one of these classname as input parameter in String format and instantiate that class.
public void instantiateclass(String Classname)
{
// this method should instantiate the given classname
}
is this possible in java reflection? or any other concepts in java?
Yes, you can do that. you can change your method to return an Object.
public Object instantiateClass(Class<?> clazz)
{
Object instance = null;
try {
instance = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return instance;
}
This can be easily done in c# by below code
private static object CreateInstanceByClassName(string className)
{
var assembly = Assembly.GetExecutingAssembly();
var type = assembly.GetTypes()
.First(t => t.Name == className);
return Activator.CreateInstance(type);
}
Above code assumes that the class is present in same assemble
Related
I'm working on legacy project and I've trapped into situation when I have to make additional init stuff with action object. In this code AdmAction is a basic interface and inside method I could have any of it's implementation. Some of implementations require additional properties must be initialized with values from utilParams.
private void initActionParams(AdmAction action, Map<String, Object> utilParams) {
if (utilParams == null) {
return;
}
utilParams.forEach((paramName, value) -> {
try {
Method setterMethod = action.getClass().getMethod(setterFor(paramName), value.getClass());
setterMethod.invoke(action, value);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}
});
}
utilParams looks like "serviceId": 10 of "ticketId": "8a30f5a7-809c-4551-8833-c2a60e4c6fd9".
Code works fine when value is an Object type (String, Integer etc.) and when setter method of AdmAction implementation consumes the same.
But there's one problem when I've got for example Integer type in utilParams and setter method in action which consumes int.
Of course code throws NoSuchMethodException
Example:
Action impl:
public class Foo implements AdmAction {
// ...
public void setServiceId(int serviceId) {
this.serviceId = serviceId;
}
}
Causes an exception.
I've tried to improve code with method search:
private void initActionParams(AdmAction action, Map<String, Object> utilParams) {
if (utilParams == null) {
return;
}
utilParams.forEach((paramName, value) -> {
try {
Method setterMethod = Arrays.stream(action.getClass().getDeclaredMethods())
.filter((Method method) -> method.getName().equals(setterFor(paramName)))
.findFirst()
.orElseThrow(NoSuchMethodException::new);
setterMethod.invoke(action, value);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}
});
I guess it's a little bit brute for actual case.
Can anybody help me find the way to write better and more aesthetic code?
You could use java.beans.Statement for this, which will do unboxing.
java.beans.Statement(action, setterFor(paramName), new Object[] {value})
.execute();
I am making a class object using the a java bean in my code. Then I am calling a particular method of that class obj
public static void runUnitTest(String className, String methodName, List<Object> inputParams, Object expectedReturnValue){
try {
// Make the class object to be tested on
Object classObj = Class.forName(className).newInstance();
Method calledMethod = classObj.getClass().getMethod(methodName,inputParams.get(0).getClass());
Object returnVal = calledMethod.invoke(classObj,inputParams.get(0));
}catch (InstantiationException | IllegalAccessException
| ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
I call it this way :
public static void main(String[] args) throws IOException {
List<Object> inputParams = new ArrayList<Object>();
inputParams.add(new BigDecimal(1234));
runUnitTest("NumberTest","getOutputNumber",inputParams,new BigDecimal(5678));
}
The code of NumberTest:
public class NumberTest{
public BigDecimal getOutputNumber(BigDecimal numberId) {
if(numberId.intValue() == 1234)
{
return new BigDecimal(5678);
}else
return new BigDecimal(0);
}
public BigDecimal getAdditionalOutputNumber(BigDecimal numberId, String additionalInfo) {
if(numberId.intValue() == 1234 && "Pass".equals(additionalInfo))
{
return new BigDecimal(5678);
}else
return new BigDecimal(0);
}
}
This works fine as I know that the method getOutputNumber has only one parameter. But when I have to call the same code for multiple methods where number of parameters differ (e.g. getAdditionalOutputNumber) I can't use the same code. I don't want to use a multiple if else or case block on the basis of size of inputParams.
Is there a generic way of calling the below :
Method calledMethod = classObj.getClass().getMethod(methodName,**?? What to pass here ??**);
Object returnVal = calledMethod.invoke(classObj,**?? What to pass here ??**);
You just have to build suitable arrays from the list of parameters to call the reflection API.
Class[] types = new Class[inputParams.size()];
int i = 0;
for(Object param:inputParams) {
types[i++] = param.getClass();
}
Method calledMethod = classObj.getClass().getMethod(methodName,types);
Object returnVal = calledMethod.invoke(classObj,inputParams.toArray());
There might be some issues with primitive types and null values.
I have this method that is supposed to set a field in the given class to the specified value:
public void setValue(Class<?> instance, String fieldName, Object value) {
try {
Field field = instance.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, value);
} catch (NoSuchFieldException e) {
if (instance.getSuperclass() != null) {
setValue(instance.getSuperclass(), fieldName, value);
} else {
try {
throw new NoSuchFieldException("Could not find field " + fieldName + " in any class.");
} catch (NoSuchFieldException ex) {
ex.printStackTrace();
e.printStackTrace();
}
}
} catch (SecurityException | IllegalArgumentException | IllegalAccessException exx) {
exx.printStackTrace();
}
}
However, it gives this error when I try to set any field:
java.lang.IllegalArgumentException: Can not set float field net.minecraft.server.v1_6_R2.Packet43SetExperience.a to java.lang.Class
I have tried using an Object(instead of an Class) but it never finds the field that I need, it only finds the fields that the Object class has.
I also tried using generics, but the same thing happened.
You need to have the actual instance of the object to pass in to the set method, not the Class object itself. Add a parameter to your method to take the actual instance:
public void setValue(Class<?> clazz, Object instance, String fieldName, Object value) {
I renamed the Class<?> parameter clazz for clarity, so it would need to be changed elsewhere:
Field field = clazz.getDeclaredField(fieldName);
And pass the actual instance to set:
field.set(instance, value);
Is it possible to dynamically call a method on a class from java?
E.g, lets say I have the reference to a class, e.g either the string: 'com.foo.Bar', or com.foo.Bar.class, or anything else which is needed..). And I have an array / list of strings, e.g [First, Last, Email].
I want to simply loop through this array, and call the method 'validate' + element on the class that I have a reference to. E.g:
MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.
item.validateFirst();
item.validateLast();
item.validateEmail();
I want the above lines of code to happen dynamically, so I can change the reference to a different class, and the names in my string list can change, but it will still call the validate + name method on whichever class it has the reference to.
Is that possible?
The simplest approach would be to use reflection
Given...
package com.foo;
public class Bar {
public void validateFirst() {
System.out.println("validateFirst");
}
public void validateLast() {
System.out.println("validateLast");
}
public void validateEmail() {
System.out.println("validateEmail");
}
}
You could use something like...
String methodNames[] = new String[]{"First", "Last", "Email"};
String className = "com.foo.Bar";
try {
Class classRef = Class.forName(className);
Object instance = classRef.newInstance();
for (String methodName : methodNames) {
try {
Method method = classRef.getDeclaredMethod("validate" + methodName);
method.invoke(instance);
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
ex.printStackTrace();
}
To look up the methods and execute them.
You will need to decide the best way to handle errors and what they mean to you, but it wouldn't be a difficult them to expand the idea to a reusable method...
Updated with idea of concept discussed in comments
Given....
public interface Validator {
public boolean isValid(Properties formProperties);
}
We can create one or more...
public class UserRegistrationValidator implements Validator {
public boolean isValid(Properties formProperties) {
boolean isValid = false;
// Required fields...
if (formProperties.containsKey("firstName") && formProperties.containsKey("lastName") && formProperties.containsKey("email")) {
// Further processing, valid each required field...
}
if (isValid) {
// Process optional parameters
}
return isValid;
}
}
Then from our input controller, we can look and valid the required forms
public class FormController ... {
private Map<String, Validator> validators;
public void validForm(String formName, Properties formProperties) {
boolean isValid = false;
Validator validator = validators.get(formName);
if (validator != null) {
isValid = validate.isValid(formProperties);
}
return isValid;
}
}
Of course you need to provide some way to register the Validators and there may be differences based on the backbone framework you are using and the parameters you can use (you don't have to use Properties, but it is basically just a Map<String, String>...)
You can write something like this... it takes name of a class as string as an argument, the method name and its arguments
private static String invoke(String aClass, String aMethod, Class<?>[] params,
Object[] args) throws Exception {
String resp = "";
Class<?> c = Class.forName(aClass);
Method m = c.getDeclaredMethod(aMethod, params);
Object i = c.newInstance();
resp = m.invoke(i, args).toString();
return resp;
}
You can also refer to the oracle tutorial on reflection ... which demonstrates how to call methods
http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
It's possible using reflection.
First, you create a new class from the FQN (fully qualified name, which is the class name including the package).
Then you iterate through your elements and invoke the "validate" methods on your item.
Class<?> clazz = Class.forName("com.foo.Bar");
Object item = clazz.newInstance();
for (String element : elements) {
Method method = clazz.getDeclaredMethod("validate" + element);
method.invoke(item);
}
You can use reflection, but my favorite method is to use beanutils, eg:
Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");
Note that your class has to conform to javabean convention. You can read more about beanutils on this blog post (disclaimer I'm the blog author)
If you know the name of the class beforehand, use Class.forName(yourClassname)
That way, you can invoke the class, and then, you can invoke its methods.
Yes, using reflection.
Using Class.getDeclaredMethod on your object
Object validator = <your object instance>;
final String[] values = {
"Item1","Item2","Item3"
}
for(final String s : values) {
Method m = validator.getDeclaredMethod("validate" + s,String.class);
try {
Object result = m.invoke(validator, s);
}
catch(ex) {}
}
All the examples I look at for reflection show creating a new instance of an unknown implementation, and casting that implementation to it's interface. The issue with this is that now you can't call any new methods (only overrides) on the implementing class, as your object reference variable has the interface type. Here is what I have:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
InterfaceType interfaceType = null;
try {
interfaceType = (InterfaceType)c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
If I only have a reference to "com.path.to.ImplementationType", and I don't know what that type might be (it is coming from a config file), then how can I use the class name to cast it to ImplementationType? Is this even possible?
This line seems to sum up the crux of your problem:
The issue with this is that now you can't call any new methods (only overrides) on the implementing class, as your object reference variable has the interface type.
You are pretty stuck in your current implementation, as not only do you have to attempt a cast, you also need the definition of the method(s) that you want to call on this subclass. I see two options:
1. As stated elsewhere, you cannot use the String representation of the Class name to cast your reflected instance to a known type. You can, however, use a String equals() test to determine whether your class is of the type that you want, and then perform a hard-coded cast:
try {
String className = "com.path.to.ImplementationType";// really passed in from config
Class c = Class.forName(className);
InterfaceType interfaceType = (InterfaceType)c.newInstance();
if (className.equals("com.path.to.ImplementationType") {
((ImplementationType)interfaceType).doSomethingOnlyICanDo();
}
} catch (Exception e) {
e.printStackTrace();
}
This looks pretty ugly, and it ruins the nice config-driven process that you have. I dont suggest you do this, it is just an example.
2. Another option you have is to extend your reflection from just Class/Object creation to include Method reflection. If you can create the Class from a String passed in from a config file, you can also pass in a method name from that config file and, via reflection, get an instance of the Method itself from your Class object. You can then call invoke(http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object, java.lang.Object...)) on the Method, passing in the instance of your class that you created. I think this will help you get what you are after.
Here is some code to serve as an example. Note that I have taken the liberty of hard coding the params for the methods. You could specify them in a config as well, and would need to reflect on their class names to define their Class obejcts and instances.
public class Foo {
public void printAMessage() {
System.out.println(toString()+":a message");
}
public void printAnotherMessage(String theString) {
System.out.println(toString()+":another message:" + theString);
}
public static void main(String[] args) {
Class c = null;
try {
c = Class.forName("Foo");
Method method1 = c.getDeclaredMethod("printAMessage", new Class[]{});
Method method2 = c.getDeclaredMethod("printAnotherMessage", new Class[]{String.class});
Object o = c.newInstance();
System.out.println("this is my instance:" + o.toString());
method1.invoke(o);
method2.invoke(o, "this is my message, from a config file, of course");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException nsme){
nsme.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (InstantiationException ie) {
ie.printStackTrace();
} catch (InvocationTargetException ite) {
ite.printStackTrace();
}
}
}
and my output:
this is my instance:Foo#e0cf70
Foo#e0cf70:a message
Foo#e0cf70:another message:this is my message, from a config file, of course
//====Single Class Reference used to retrieve object for fields and initial values. Performance enhancing only====
Class<?> reference = vector.get(0).getClass();
Object obj = reference.newInstance();
Field[] objFields = obj.getClass().getFields();
I'm not absolutely sure I got your question correctly, but it seems you want something like this:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
T interfaceType = null;
try {
interfaceType = (T) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Where T can be defined in method level or in class level, i.e. <T extends InterfaceType>
As an addendum to akf's answer you could use instanceof checks instead of String equals() calls:
String cname="com.some.vendor.Impl";
try {
Class c=this.getClass().getClassLoader().loadClass(cname);
Object o= c.newInstance();
if(o instanceof Spam) {
Spam spam=(Spam) o;
process(spam);
}
else if(o instanceof Ham) {
Ham ham = (Ham) o;
process(ham);
}
/* etcetera */
}
catch(SecurityException se) {
System.err.printf("Someone trying to game the system?%nOr a rename is in order because this JVM doesn't feel comfortable with: ā%sā", cname);
se.printStackTrace();
}
catch(LinkageError le) {
System.err.printf("Seems like a bad class to this JVM: ā%sā.", cname);
le.printStackTrace();
}
catch(RuntimeException re) {
// runtime exceptions I might have forgotten. Classloaders are wont to produce those.
re.printStackTrace();
}
catch(Exception e) {
e.printStackTrace();
}
Note the liberal hardcoding of some values. Anyways the main points are:
Use instanceof rather than equals(). If anything, it will co-operate better when refactoring.
Be sure to catch these runtime errors and security ones too.
You want to be able to pass in a Class and get a type-safe instance of that class? Try the following:
public static void main(String [] args) throws Exception {
String s = instanceOf(String.class);
}
public static <T> T instanceOf (Class<T> clazz) throws Exception {
return clazz.newInstance();
}
If you knew the Class of ImplementationType you could create an instance of it. So what you are trying to do is not possible.