How to get an instanced Object from an incomplete class name? - java

world! I need to instantiate an Object from the name of its Class. I know that it is possible to do it, this way
MyObject myObject = null;
try {
Constructor constructor = Class.forName( "fully.qualified.class.name" ).getConstructor(); // Get the constructor without parameters
myObject = (MyObject) constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
The problem is that the name of my class is not fully qualified. Is there a way to get the complete name by only knowing the short name?

MyObject myObject = null;
for (Package p : Package.getPackages()) {
try {
myObject = Class.forName(p.getName() + "." + className).newInstance();
break;
} catch (ClassNotFoundException ex) {
// ignore
}
}
The Package.getPackages() call will give you every package known to the current classes ClassLoader and its ancestors.
Warning: this will be expensive because you are repeatedly throwing and catching exceptions. It may be possible to speed it up by testing:
this.getClass().getClassLoader().findResource(binaryClassName) != null
before calling Class.forName(...) or the equivalent.

Try this repeatedly for a package search path. ;)
String[] packages = ...;
String className = ...;
MyObject myObject = null;
for(String p : packages)
try {
myObject = Class.forName(p + '.' + className).newInstance();
break;
} catch (Exception ignored) {
}

Related

Java: check if a class exists and call a specific method if it exists

Is there a way to do the following? Check if a class exists (in the same package) and if it does exist, check if a particular method exists, and if so, calling it?
Say that I have class X. In some method of class X, I want to do the following:
if (class Y exists) { //Maybe use Class.forName("Y")?
if ( Y has method a(String, String) ) {
call Y.a("hello", "world");
}
}
Is such a thing possible? And is doing such a thing reasonable? Thanks.
Is such a thing possible? And is doing such a thing reasonable?
Thanks.
Of course it is possible.
If you develop a program or a library that has to discover dynamically some classes, it is a very reasonable thing.
If it is not the case, it could not be.
If your need makes sense, you should ask you an additional question : should you invoke a static or instance method ?
Here is a sample example with both solutions :
ReflectionClass that contains the logic using reflection :
import java.lang.reflect.Method;
public class ReflectionCalls {
public static void main(String[] args) {
new ReflectionCalls();
}
public ReflectionCalls() {
callMethod(true);
callMethod(false);
}
private void callMethod(boolean isInstanceMethod) {
String className = "DiscoveredClass";
String staticMethodName = "methodStatic";
String instanceMethodName = "methodInstance";
Class<?>[] formalParameters = { int.class, String.class };
Object[] effectiveParameters = new Object[] { 5, "hello" };
String packageName = getClass().getPackage().getName();
try {
Class<?> clazz = Class.forName(packageName + "." + className);
if (!isInstanceMethod) {
Method method = clazz.getMethod(staticMethodName, formalParameters);
method.invoke(null, effectiveParameters);
}
else {
Method method = clazz.getMethod(instanceMethodName, formalParameters);
Object newInstance = clazz.newInstance();
method.invoke(newInstance, effectiveParameters);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
DiscoveredClass (the class we manipulate in the example)
package reflectionexp;
public class DiscoveredClass {
public static void methodStatic(int x, String string) {
System.out.println("static method with " + x + " and " + string);
}
public void methodInstance(int x, String string) {
System.out.println("instance method with " + x + " and " + string);
}
}
Output :
instance method with 5 and hello
static method with 5 and hello
Yes, this can be done. I've created a Test class in the same Package as the current class.
import java.lang.reflect.Method;
public class Sample {
public static void main(String[] args) {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (clazz == null) {
System.out.println("class not found. Go eat some waffles and correct the name");
return;
}
Method m = null;
try {
m = clazz.getMethod("foo", null);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (m == null) {
System.out.println("method not found. Go eat some waffles and correct the name");
return;
}
Test t;
try {
t = (Test) clazz.newInstance();
m.invoke(t, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Test {
static {
System.out.println("test...");
}
public void foo() {
System.out.println("foo");
}
}
O/P :
test...
foo
You can use Class.forName:
try {
Class yourClass = Class.forName( "classname" );
Object o = yourClass.newInstance();
} catch( ClassNotFoundException e ) {
//Throw error or whatever
}
To check if a method exists you could use the NoSuchMethodError e in a try/catch
You can do this using reflection, however it isnt really practical unless you are trying to access classes that potentially will not be present at runtime or if you are trying to access private or hidden fields. Example below.
public static void reflectionDemo(){
//Here we attempt to get the common URI class
//If it is found, we attempt to get the create method
//We then invoke the create method and print the class name of the result.
try {
Class<?> uriClass = Class.forName("java.net.URI");
//getMethod(String name, Class<?>... args);
java.lang.reflect.Method create = uriClass.getMethod("create", String.class);
//The first parameter is null because this is a static method.
//invoke(Object target, Object... args);
System.out.println(create.invoke(null, "some/uri").getClass());
//Will print class java.net.URI
} catch (ClassNotFoundException e) {
// If class doesnt exist
e.printStackTrace();
} catch (NoSuchMethodException e) {
// If method doesnt exist
e.printStackTrace();
} catch (SecurityException e) {
// See Javadoc
e.printStackTrace();
} catch (IllegalAccessException e) {
// From invoke
e.printStackTrace();
} catch (IllegalArgumentException e) {
// From invoke
e.printStackTrace();
} catch (java.lang.reflect.InvocationTargetException e) {
// From invoke
e.printStackTrace();
}
}
To find whether a class exists, you can use the forName() method on Class.
To find whether a method exists, you can use the getMethod() method on Class.
Documentation here:
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String)
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)
For your class problem, you'd want to use code like:
try {
Class.forName("Y");
}
catch (ClassNotFoundException e) {
}
For your method problem, you'd want to use code like:
try {
Class.getMethod(a);
}
catch (NoSuchMethodException e) {
}
You can check if the Class exists with Class.forName("classname");
See this SO question: Check if class exists somewhere in package
If a method exists can be catched with NoSuchMethodError in your try/catch.
See this SO question: Check if method exists at Runtime in Java
try {
Object object = Class.forName("Y").newInstance();
object.a(String, String);
} catch( ClassNotFoundException | NoSuchMethodError ex) {
//do Something else
}

How to create an instance of newly added class in java at runtime

I have to write a different class to read a file of different kind. Now project is deployed on client side. And we have to give support to new files. so we have to create a new class and also modify in service class to create a new object of newly added class. Writing a new class for new type of class is fine. But I do not want to change service class each time. Is there any solution for this kind of problem? Thanks in advance.
Update 1: here is code of service class
#Service("StockistServiceImpl")
public class StockistServiceImpl implements StockistService {
#Override
#Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
public JSONArray saveStockistOrder(Integer stockistId,
MultipartFile[] orderFile, String orderNumber, String orderDate,
String partyCode,String order,Integer userId)
{
List<Pair<String, Integer>> charList = new ArrayList<Pair<String, Integer>>();
Properties code1 = new Properties();
try {
code.load(StockistServiceImpl.class.getClassLoader().getResourceAsStream("categoryOfFile.properties"));
}
catch (IOException e) {
//System.out.println("error in loading divisionNamePdfCode.properties");
e.printStackTrace();
}
String readDuelListedTxtFile = code.getProperty("readDuelListedTxtFile");
String readStartLineLengthForOrderTxtFile = code.getProperty("readStartLineLengthForOrderTxtFile");
String ReadFileWithNoStartLineTxtFile = code.getProperty("ReadFileWithNoStartLineTxtFile");
String ReadStartLineLengthForQtySingleListTxtFile = code.getProperty("ReadStartLineLengthForQtySingleListTxtFile");
if (readDuelListedTxtFile.contains(partyCode
.trim())) {
charList.addAll(dualListText
.readDuelListedTxtFile(
fileName, codeDetails));
}
else if (readStartLineLengthForOrderTxtFile.contains(partyCode
.trim())) {
charList.addAll(lineLength
.readStartLineLengthForOrderTxtFile(
fileName, codeDetails));
}
else if (ReadFileWithNoStartLineTxtFile.contains(partyCode
.trim())) {
T_FileWithNoStartLine noStartLine = new T_FileWithNoStartLine();
charList.addAll(noStartLine
.readFileWithNoStartLineTxtFile(
fileName, codeDetails));
}
else if (ReadStartLineLengthForQtySingleListTxtFile.contains(partyCode
.trim())) {
T_StartLineLengthForQtySingleList noStartLine = new T_StartLineLengthForQtySingleList();
charList.addAll(noStartLine
.readStartLineLengthForQtySingleListTxtFile(
fileName, codeDetails));
}
}
Update 2: here is property file from where we know that what is file type for a stockist.
#fileType,stockistCode
fileType1=ST001,ST009
fileType2=ST002,ST005,ST006
fileType3=ST003,ST007
fileType4=ST004,ST008
and i want to add a new property file like this to map a file type with class name so if a new class is added and then we will not have to edit service class.
#fileType,fullyqualifiedclassName
fileType1=FullyQualifiedClassName1
fileType2=FullyQualifiedclassName2
fileType3=FullyQualifiedClassName3
fileType4=FullyQualifiedclassName4
Separate the creation of the file readers objects and the service class.
public class BuildFileReader() {
FileReader getReader(String xyz) {
FileReader reader;
...
your logic
reader = new WhatEverReaderYouWant();
...
return reader;
}
}
The service class simply asks the BuildFileReader which FileReader to use and doesn't need to change anymore.
public class StockistServiceImpl {
...
BuildFileReader bfr = new BuildFileReader();
FileReader fileReader = bfr.getReader(xyz);
fileReader.readFile(fileName, codeDetails);
...
}
If you need only one type of file reader per client, you could configure your BuildFileReader for each client.
If you need more than one type of file reader per client, define an interface for each type an add a getReaderXYZ() function for each needed type in BuildFileReader.
Instance can be created at runtime using reflection in java, please have a look at below post:
Creating an instance using the class name and calling constructor
Finally after doing some code changes and adding property file for mapping class names with property of file here is the code and working fine.
#Service("StockistServiceImpl")
public class StockistServiceImpl implements StockistService {
List<Pair<String, Integer>> charList = new ArrayList<Pair<String, Integer>>();
Map<String,String> mapTxtFile = new HashMap<String, String>();
Properties fileTypeProperties = new Properties();
Properties matchClassNameProperties = new Properties();
try {
fileTypeProperties.load(StockistServiceImpl.class.getClassLoader().getResourceAsStream("fileTypeProperties.properties"));
}
catch (IOException e) {
//e.printStackTrace();
}
try {
matchClassNameProperties.load(StockistServiceImpl.class.getClassLoader().getResourceAsStream("matchClassNameProperties.properties"));
}
catch (IOException e) {
//e.printStackTrace();
}
for (String key : fileTypeProperties.stringPropertyNames()) {
String value = fileTypeProperties.getProperty(key);
mapTxtFile.put(key, value);
if(value.contains(partyCode.trim())){
String className = matchClassNameProperties.getProperty(key);
try {
Class clazz = Class.forName(className);
try {
TxtFile objToReadTxtFile = (TxtFile) clazz.newInstance();
charList= objToReadTxtFile.readTxtFile(fileName, codeDetails);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
//read normally else block
}
}
}
Now it is working fine.But for that i created an interface for reading txt file which has readTxtFile method. and all other classes now implement this interface.

How to change an ATM class during run time (Java Reflection)

There is an ATM GUI .class.
In the ATM class, if the user click swipe, it will use Java reflection to dynamically call my Card.class.
In the ATM class there is this variable:
int userBalanceField = 100;
I am trying to dynamically change it to Integer.MAX_VALUE.
Here is the swipe function in ATM:
Object object;
Class class_ = null;
ClassLoader classLoader;
this.printToScreen("Loading Card");
String string = "." + File.separator + "Card.class";
File file = new File(string);
ClassLoader classLoader2 = classLoader = ClassLoader.getSystemClassLoader();
try {
object = new URL("file:" + System.getProperty("user.dir") + File.separator + "Card.class");
class_ = Card.class;
}
catch (MalformedURLException var6_7) {
var6_7.printStackTrace();
}
object = "Card";
this.printToScreen("Reading card data and verifying ATM");
try {
Method method = class_.getMethod("swipe", ATM.class);
Data data = (Data)method.invoke(null, this);
if (data == null) {
this.printToScreen("Machine considered invalid");
} else {
this.user = data;
this.tempEntry = "";
this.screenState = 2;
this.updateScreen();
}
}
catch (SecurityException var8_11) {
this.printToScreen("Security Exception when swiping card.");
}
catch (NoSuchMethodException var8_12) {
this.printToScreen("No Such method exception when swiping card.");
}
catch (IllegalArgumentException var8_13) {
this.printToScreen("Illegal Argument exception when swiping card.");
}
catch (IllegalAccessException var8_14) {
this.printToScreen("Illegal Access exception when swiping card.");
}
catch (InvocationTargetException var8_15) {
this.printToScreen("Invocation Target exception when swiping card.");
}
Here is my attempt.
public static ATM.Data swipe(ATM anATM){
Class atmClass = anATM.getClass();
try {
Field moneyInMachineField = atmClass.getDeclaredField("moneyInMachine");
System.out.println("Loading field..." + moneyInMachineField.getName());
Field userBalanceField = atmClass.getDeclaredField("userBalance");
userBalanceField.setAccessible(true);
ATM.Data result = new ATM.Data(cardNumber, accountNumber, name, pinNumber);
userBalanceField.set(result, Integer.MAX_VALUE);
return result;
} catch (IllegalAccessException
| NoSuchFieldException
| SecurityException e) {
e.printStackTrace();
}
return null;
}
I keep getting "Invocation Target exception when swiping card."
The syntax that you are using is for the creation of new non-static inner classes. Data is a static inner class of ATM, so you want to do the following:
ATM.Data result = new ATM.Data(cardNumber, accountNumber, name, pinNumber);
According to the Java Docs
For example, to create an object for the static nested class, use this
syntax:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
If Data was non-static, it would contain a specific reference to ATM (which would give it the ability to refenence AMT.this.userBalance), but it is only used as a POJO.
In addition to the above, you are setting the field incorrectly. When calling field.set() you need to provide it with the object which contains the field and the value you want to set it to.
In your case it would be:
userBalanceField.set(anATM, Integer.MAX_VALUE);
See Java doc
The code
Field userBalanceField = atmClass.getDeclaredField("userBalance");
suggests that userBalance is a field of ATM, but
ATM.Data result = new ATM.Data(cardNumber, accountNumber, name, pinNumber);
userBalanceField.set(result, Integer.MAX_VALUE);
tries to set the field userBalance of ATM.Data object.
If the field userBalance is in ATM.Data, try:
Field userBalanceField = ATM.Data.class.getDeclaredField("userBalance");
The InvocationTargetException wraps all exceptions thrown by reflected methods. This is because the Reflection API is oblivious to the types of exceptions that methods can throw.
Try catching:
InvocationTargetException
And then use:
getCause();
For example:
catch (InvocationTargetException e) {
System.out.println(e.getCause();
}
This will tell you what is actually going wrong. It will also help us to debug your code.

Can I pass parameters to my dynamically created classes?

I am successfully loading a class from an external MyClass.class file at runtime, and am able to call it's methods assuming I know the name of them, which I do.
The problem I'm having is I cannot figure out how to pass a parameter to the constructor of the class I am loading.
How can I modify this to pass a parameter to MyClass's constructor? Also, how can I access MyClass's public variable: infoToAccess?
Here are the files I'm working with. (Keep in mind, ClassLoaderExample.pde was written for Processing, but other than sketchPath("") and the lack of a main function, it is identical.
ClassLoaderExample.pde: The main file that loads the class:
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.lang.ClassLoader;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
/////// FILE STRUCTURE /////
// ClassLoaderExample //
// --this file //
// --tmp //
// ----MyClass.class //
////////////////////////////
// TODO
// Send parameter to MyClass constructor (by reference)
// Get public int number from MyClass
void setup()
{
String className = "MyClass";
Object instance;
Method updateMethod;
// sketchPath("") returns the directory this file is in
File file = new File(sketchPath(""));
try
{
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader classLoader = new URLClassLoader(urls);
Class<?> loadedClass = classLoader.loadClass("tmp."+className);
try
{
instance = loadedClass.newInstance();
updateMethod = loadedClass.getDeclaredMethod("update");
// Calls MyClass's update() method
try
{
updateMethod.invoke(instance);
}
catch (InvocationTargetException e) {System.out.println(e);}
catch (IllegalAccessException e) {System.out.println(e);}
}
catch (InstantiationException e) {System.out.println(e);}
catch (IllegalAccessException e) {System.out.println(e);}
catch (NoSuchMethodException e) {System.out.println(e);}
}
catch (MalformedURLException e) {System.out.println(e);}
catch (ClassNotFoundException e) {System.out.println(e);}
}
MyClass.java: The class I am loading:
package tmp;
public class MyClass
{
public int infoToAccess = 1337;
public MyClass(int i)
{
System.out.println("MyClass constructor was called with numebr: " + i);
}
public void update()
{
System.out.println("Update was called.");
}
}
Thanks for any help with this!
you can use the class you loaded to get hold of the constructor
you need an use that to create a new instance.
import java.lang.reflect.Constructor;
...
Class<?> loadedClass = classLoader.loadClass("tmp."+className);
try {
Constructor<?> ctor=loadedClass.getConstructor(int.class);
ctor.newInstance(42);
...
}
...
You need to use reflection for both of the things you asked about:
Class<?> loadedClass = classLoader.loadClass("tmp." + className);
Object oInstance = null;
try {
Constructor<?> c = loadedClass.getConstructor(Integer.class);
oInstance = c.newInstance(10);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
//Handle the possibility that you cannot access this constructor
}
To access the public field of your object:
try {
Field field = loadedClass.getField("infoToAccess");
int fieldValue = field.getInt(oInstance);
} catch (NoSuchFieldException | IllegalAccessException e) {
//Handle the possibility that you cannot access this field
}
As mentioned in the link I wrote in the comments, you can pass parameters in this call
updateMethod = loadedClass.getDeclaredMethod("update", parameters go here);
then you should be able to invoke the method with a parameter(s)
If you want to pass arguments to the constructor you cannot use getInstance(), you have to get the constructor object and pass the parameters there.
Example:
Constructor constructor = aClass.getConstructor(new Class[]{String.class});
MyObject myObject = (MyObject) constructor.newInstance("constructor-arg1");
See tutorial here: Java Reflection - Constructors

Finding the cluster that an instance got assigned to with Weka

Im using an EM clusterer with an AddCluster Filter in order to see what instances are getting assigned to the different clusters after training. Below is the code that I'm using. I'm faily sure that I am applying the filter correctly but once I have the new Instances I still dont know how to get the cluster info from them. Im sure its just a simple getBlah() call but I'm just not locating it. Thanks in advance.
public Cluster()
{
clusterer = new EM();
filter = new AddCluster();
try
{
clusterer.setMaxIterations(100);
clusterer.setNumClusters(20);
filter.setClusterer(clusterer);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void buildCluster(String fileName)
{
try
{
DataSource source = new DataSource(fileName);
inst = source.getDataSet();
filter.setInputFormat(inst);
inst = AddCluster.useFilter(inst, filter);
}
catch (Exception e)
{
e.printStackTrace();
}
}
I think you should use "Dictionary" Class. Here is my example code:
Enumeration clusteredInst = data_to_use.enumerateInstances();<br>
Dictionary<Integer, ArrayList<Instance>> clusteredSamples = new ashtable<>();
while (clusteredInst.hasMoreElements()) {<br>
Instance ins = (Instance) clusteredInst.nextElement();<br>
int clusterNumb = em.clusterInstance(ins);<br>
ArrayList<Instance> cls = null;<br>
cls = clusteredSamples.get(clusterNumb);<br>
if (cls != null) {<br>
cls.add(ins);<br>
} else {<br>
cls = new ArrayList<>();<br>
cls.add(ins);<br>
//you add elements to dictionary using put method<br>
//put(key, value)<br>
clusteredSamples.put(clusterNumb, cls);<br>
}
}
And you also can retrieval your data from dictionary by call it's Key.

Categories