Create Object using the value of a Java variable - java

I need help I need to know if Java allows to create an object dynamically, using the value of a variable.
Example
// I have 2 classes:
public class Audit {
private Long idAudit
// constructors, get and set
}
publish class Example {
private Long idExample
// constructors, get and set
}
-------------------------------------------------- -----
// create Audit and Example class object
Audit objAudit = new Audit ();
Example objExample = new Example ();
my question is the following can you create an object either of type Audit or example using the value of a variable as I try to do in the following example. Example:
String className = "Audit"; // variable that contains the class of the Object to create
className auditObject = new ClassName (); // I use the variable classname to create the desired object
Clearly I get an error trying to create the object that way, my question is can I create an object dynamically or some other option to try to achieve what I need. Thank you

Reflection is what you are searching for
final String className = "Audit";
final Class<?> clazz = Class.forName(className);
final Object o = clazz.getConstructor().newInstance();

There are several ways you can do this.
One is called reflection, and I will let you read about it on your own.
The other one is called a factory pattern. You can create a class called ObjectFactory. in that class you will have a method public Object createObject(String type).
In the method you can check if the type you received is one of your known types, and based on the type you can create the instance of the correct class. It is better of your classes implement the same interface. Then of course your method would return the instance of that interface (or a common base class).

Related

Casting a String to another type as a parameter of a method in Java reflection

I am trying to pass a value to a method by means of reflection in Java.
Namely, say we have string
String value = (some string representation of a value of type Type);
Say, we have a class with no-args-contructor, a single field int field and a single method, a setter method setTheField:
public class SomeClass{
private SomeType field;
SomeClass(){};
public void setTheField(SomeType parameter){
this.field = parameter
}
}
where SomeType of field may be primitive, wrapper or LocalDate / LocalDateTime.
If I take the setter (say):
Method setter = SomeClass.getClass().getDeclaredMethods()[0];
and then find out its parameters (say):
parametersList = Arrays.stream(setter.getParameters())
.collect(Collectors.toList());
Then if check if the setter requires a single parameter:
if (parametersList.size() != 1) {
throw new IllegalArgumentException("Setter named = " +
setter.getName() +
" is not a single parameter setter!");
}
What I really want to do then, is to pass string to 'setter' on some object SomeClass object = new SomeClass(); as setter.invoke(object, value); and I need somehow to cats String value to SomeType but I can not figure out how to do it uniformly.
Though, it seems a standard situation to appear and I hope someone more enlightened then me in Java can quickly figure out what to do.
Any suggestions are welcome.
Addendum:
I elaborate some more here.
The task I am trying to do is the following. Suppose I have an annotations #Column{String name} targeted to methods (or fields). Suppose I also have some domain class SomeClass with some setters (fields) annotated as #Column. I have to read from CSV top row with column names (headers to link data to the annotation's name), then I have to return a list of objects of my domain class SomeClass. This is the reason I am using reflection and I see no other way around.
Without more context this looks like a design problem. Why go through all the work to grab a setter by reflection and given a String, get a value compatible with the setter argument's type? If there's no other way around this problem, it is not possible to just cast a String to some other type. One possibility is making a factory class.
Assumption: the setter's argument type is some class called MyType.
class ArgumentFactory {
MyType valueFor(String in) {
// based on the string's value, put the conversion logic here
if (in == null || in.isEmpty()) {
return new MyType();
}
// add other cases as necessary ...
}
}
Then you have
ArgumentFactory factory = new ArgumentFactory();
// ...
String value = "qwerty";
setter.invoke(object, argumentFactory.valueFor(value));

How to use methods from another class, called by the client

I am making a program that lets the user call a class, like it takes a string input, then calls the run() method of that class, is there any way to do that? I was hoping something like:
String inp=new Scanner(System.in).nextLine();
Class cl=new Class(inp);
cl.run();
I know that the code isn't correct, but that is my main idea
Creating and using a class by name requires some preconditions:
Full name of the class must be used, including package name.
You need to know the parameters of the constructor. Usually the no-arguments constructor is used for a such use case.
(Optional) You need an interface this class must implement which declares the method "run" (or any other methods you want to use).
An example with a subclass of Runnable:
String className = "some.classname.comes.from.Client";
Class<Runnable> clazz = (Class<Runnable>) Class.forName(className);
Runnable instance = clazz.getConstructor().newInstance();
instance.run();
If you don't have a common interface, you can invoke the method using reflection:
Class<Object> clazz = (Class<Object>) Class.forName(className);
Object instance = clazz.getConstructor().newInstance();
clazz.getMethod("run").invoke(instance);
or using method with parameters:
Integer p1 = 1;
int p2 = 2;
clazz.getMethod("methodWithParams", Integer.class, Integer.TYPE).invoke(instance, p1, p2);
String Variable can't be a reference for the Class.
to to a something like changing the object depends on the input
you can use polymorphism and design patterns (Factory Pattern)

Better way of initialising List of abstract class with inheriting class names

Possibly duplicate, I have an abstract class called FormField which contains some common properties like field value, field label, etc.
My application renders fields dynamically based on an APIs result. So, I can get a JSON which says fieldX of type String, fieldY of type Date, etc. Based on the type I want to automatically render the correct field. I was already able to abstract the logic using an abstract class with static blocks. The abstract class has code like:
// Common fields
public String label;
public String value;
public static Map<String, Class> fieldTypes = new HashMap<>();
static {
FormField.fieldTypes.put("String", StringField.class);
FormField.fieldTypes.put("Date", DateField.class);
}
I originally wanted to put the static block in StringField, DateField to add themselves automatically to the fieldTypes array in their parent FormField abstract class but that didn't work since I do not explicitly call these field type classes anywhere so their static blocks never get called at all. I figured the alternative would be to just initialize each inside the FormField static block.
The way the app works, it fetches the data from the API and for each field it calls a create method which takes the type identification string i.e. String, Date and based on that my FormField class initializes the code using this:
public static FormField create(String type, String label) {
Class aClass = fieldTypes.get(type);
if(aClass == null)
return null;
FormField field = null;
try {
field = (FormField) aClass.newInstance();
field.label = label;
return field;
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
}
}
Then it calls the render method which renders the UI and does further operations. I want to eliminate the static block and want hashmap to fill itself automatically whenever I create (not initialize) a new concrete class that extends it. This would help me to create new concrete classes whenever my business logic needs it i.e. tomorrow I can add any new field type such as photo and just write the specific logic for that rather than having to add a line to the static block each time. I wouldn't mind a better solution which eliminates fieldTypes hashMap too. I know there's some way through reflection to go thro the entire 'fieldTypes' subpackage and initialize one after another but I don't want that (nor do I know how it would be coded) since I feel is bad practice. Any better solutions to this problem?
I can think of two solutions for this problem:
1) This requires an external lib: https://github.com/ronmamo/reflections
Using this libray you can get all instances of a parent class, I assume Field as follows:
Reflections reflections = new Reflections("your.project.fields");
Set<Class<? extends Field>> allClasses =
reflections.getSubTypesOf(Field.class);
For your case, whenever you introduce a new class to your codebase, this reflective code runs, discovers the class and use it accordingly.
2) Whenever you introduce a new class, you update a file, which contains all BlahField classes. You can initialize your map using this class but, I have to admit that this is less intriguing.

Dynamically creating and populating class inside method in java

Though my question seems repetition, but I am new to Reflections and could find solution to the exact problem.
I need to write a method, which any class can call to populate its data. For simplicity, I created a class say MappingHelper, with a Factory like method 'Create' which will create its own instance. I need to then populate this instance and return it.
public final Class MappingHelper{
public final Object getBENodeData(Class<?> classRef, String className){
Class myClass = Class.forName(classRef.getName());
Method method = classRef.getMethod("Create",(Class<?>[])null);
Object obj = method.invoke(null, (Object[]) null);
}
}
I need to typecast obj to same type as of 'classRef' so that I can call its instance methods.
Could someone help?
What you're trying to do is not possible with reflection and with your current setup. Even if you manage to cast the object to classRef, you wouldn't know what instance methods to call since getBENodeData presumably can take any type.
What you can do is call the method from a location where the type is known, and cast to it.
Object obj = getBENodeData(MyType1.class, MyType1.class.getName());
MyType1 myType1 = (MyType1) obj;
myType1.setId(..);
Object obj2 = getBENodeData(MyType2.class, MyType2.class.getName());
MyType2 myType2 = (MyType2) obj2;
myType2.setName(..);

String to new object with parameters

How do i create a new instance of an object from a string?
I want to do this:
Event event = new Event("hello");
event.setName("nice!");
but only having
String object = "Event";
String object_variable_name = "event";
String object_params = "hello";
Is this possible?
You can instantiate a class with the reflection API. But you need the full class name, the simple name (= with no constructor) is not enough.
Class clazz = Class.forName("com.example.Event");
Constructor constructor = clazz.getConstructor(String.class);
Object instance = constructor.newInstance("hello");
Assigning it to a variable where the variables name and type are stored in Strings is not possible. The usual pattern to implement this is to use a map:
Map<String, Object> events = new HashMap<String, Object>();
events.put("event", event);
You can use java.lang.Class's getConstructor isnstead.
Here is how you get the class instance (so you can call the constructor): How to get a Class Object from the Class Name in Java
Now you can you the Beans API to get the getter for the property name. See this question: Java Reflection: Instantiate a new object with specified type
Or you can use reflectasm or reflections or commons-beanutils to make your life much more simple

Categories

Resources