I have some value which I get in string format from a file.
For example, in the File A I have:
id = 342
name = Jonatan
country = USA
In addition, I have class: person with the next fields:
String id;
String name;
String country;
String grades;
String location;
and I have getter and setter for all the fields.
Now, I want to create a new instance of person, which represents Jonatan.
But - I don't want to update all the field, only the fields I need.
So, what I want to do is the next: get the details from the file, and then for every one do set, and update the correct value. For example, setName(Jonatan). The problems is that my name is in a String format. so I cant do setName - because name is in a string format, and Java doesn't give me the option of call a method in a string format.
There is easy way to it?
You might have a look at Apache BeanUtils
The application is pretty simple - to call setId("42") of a person call:
PropertyUtils.setSimpleProperty(person, "id", "42");
I like #michael_s's answer with BeanUtils. If you want to do it without, you can write:
Person person = new Person();
Properties properties = new Properties();
properties.load(new FileInputStream("the.properties"));
for (Object key : properties.keySet()) {
String field = (String) key;
String setter = "set" + field.substring(0, 1).toUpperCase() + field.substring(1);
Method method = Person.class.getMethod(setter, String.class);
method.invoke(person, properties.get(key));
}
Not that the stream should be closed after using it, and that this short example only works for String properties.
Using java reflection you can determine what methods/fields are available.
You can use this example to pass your key/value pairs into the doReflection method to set the new values of your properties in the instance of the Bean-class.
public class Bean {
private String id = "abc";
public void setId(String s) {
id = s;
}
/**
* Find a method with the given field-name (prepend it with "set") and
* invoke it with the given new value.
*
* #param b The object to set the new value onto
* #param field The name of the field (excluding "set")
* #param newValue The new value
*/
public static void doReflection(Bean b, String field, String newValue) throws NoSuchMethodException,
SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<? extends Bean> c = b.getClass();
Method id = c.getMethod("set" + field, String.class);
id.invoke(b, newValue);
}
public static void main(String... args) throws NoSuchMethodException, SecurityException, IllegalArgumentException,
InvocationTargetException, IllegalAccessException {
Bean bean = new Bean();
System.out.println("ID before: " + bean.id);
doReflection(bean, "Id", "newValue");
System.out.println("ID after: " + bean.id);
// If you have a map of key/value pairs:
Map<String, String> values = new HashMap<String, String>();
for(Entry<String, String> entry : values.entrySet())
doReflection(bean, entry.getKey(), entry.getValue());
}
Related
I have a nested SQL query to fetch employee details using their ID.
Right now I am using BeanListHandler to fetch data as a List<Details> but want to store it as a Map<String, Details> where the ID I originally pass needs to be the key for easy retrieval instead of searching the List with streams every time.
I have tried to convert to Maps but I am not sure of how to map the ID as String nor how to get the original ID passed to the inner Query as a column in the final result.
MainTest.java:
String candidateId = "('1111', '2222', '3333', '4444')";
String detailsQuery =
"select PARTNER, BIRTHDT, XSEXM, XSEXF from \"schema\".\"platform.view/table2\" where partner IN \r\n"
+ "(select SID from \"schema\".\"platform.view/table1\" where TYPE='BB' and CLASS='yy' and ID IN \r\n"
+ "(select SID from \"schema\".\"platform.view/table1\" where TYPE='AA' and CLASS='zz' and ID IN"
+ candidateId + "\r\n" + "))";
Map<String, Details> detailsView = queryRunner.query(conn, detailsQuery, new DetailsViewHandler());
Details.java:
public class Details {
private String candidateId;
private String birthDate;
private String maleSex;
private String femaleSex;
// getter and setter
}
DetailsViewHandler.java:
public class DetailsViewHandler extends BeanMapHandler<String, Details> {
public DetailsViewHandler() {
super(Details.class, new BasicRowProcessor(new BeanProcessor(getColumnsToFieldsMap())));
}
public static Map<String, String> getColumnsToFieldsMap() {
Map<String, String> columnsToFieldsMap = new HashMap<>();
columnsToFieldsMap.put("PARTNER", "candidateId");
columnsToFieldsMap.put("BIRTHDT", "birthDate");
columnsToFieldsMap.put("XSEXM", "maleSex");
columnsToFieldsMap.put("XSEXF", "femaleSex");
return columnsToFieldsMap;
}
}
Is there a way to get the ID (candidateId) in the result and what am I missing in terms of creating the key-value pairing ?
From the doc https://commons.apache.org/proper/commons-dbutils/apidocs/org/apache/commons/dbutils/handlers/BeanMapHandler.html
of constructor which you are using
public BeanMapHandler(Class<V> type,
RowProcessor convert)
// Creates a new instance of BeanMapHandler. The value of the first column of each row will be a key in the Map.
Above should work.
You can also try overriding createKey like so
protected K createKey(ResultSet rs)
throws SQLException {
return rs.getString("PARTNER"); // or getInt whatever suits
}
I'm currently working on an application that will be used to power on/off a device (server) over SSH. Now I use a property file with the following settings:
command.power_on.name = Power on
command.power_on.host = host.com
command.power_on.user = user
command.power_on.password = password
command.power_on.port = 22
command.power_on.timeout = 10000
command.power_on.command = power on command
command.power_off.name = Power off
command.power_off.host = host.com
command.power_off.user = user
command.power_off.password = password
command.power_off.port = 22
command.power_off.timeout = 10000
command.power_off.command = power off command
I want to loop through all the commands and put them into List, Array, Object, Custom Object or whatever is possible.
PSEUDO Code:
String[] commands = propertiesConfiguration.getKeys("command");
for (String command : commands) {
CommandModel[] commandModel = command;
/* Will return two command models with the power_on and power_off attributes.
(name, host, user, password, port, timeout and command) */
}
And as result I want to get something like this (like in XML):
Command[] command; // Array with all the commands.
System.out.println(command[0].toString()); // Will print the "power_on" attributes.
System.out.println(command[1].toString()); // Will print the "power_off" attributes.
CommandModel commandModel = new CommandModel(); // The command model with queries (select, select all and update).
Command powerOn = commandModel.getCommand("power_on"); // Will return the command "power_on" with their attributes (name, host, user, password, port, timeout, command).
Command powerOff = commandModel.getCommand("power_off"); // Will return the command "power_off" with their attributes (name, host, user, password, port, timeout, command).
Command[] command = commandModel.getAll(); // Will return an array of all the commands.
I know this is possible with XML based structures, but is this also possible with a property based file? I have only 2 commands, I thought a property file will be enough for this. Or should I use a XML file?
All feedback, suggestions etc are welcome. Thank you in advance!
You can loop all of your properties using the Properties class.
Have a look at ResourceBundle class here.
The getKeys() method will return a Enumeration of String.
You can also get the values by using getString(key) method. It accepts a key as a parameter.
The following code sample will add the requested output objects in a map, having as key the name of the two wanted commands (poweroff and poweron). The fields are set using reflection.
Taking into consideration that the properties file is in the same folder where the application is run the following code sample will read all properties defined in the properties file.
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
InputStream is = Main.class.getResourceAsStream("command.properties");
Properties properties = new Properties();
// the output map that will contain the results
// the poweroff related content for key "poweroff"
// the poweron related content for key "poweron"
Map<String, Command> commands = new HashMap<>();
properties.load(is);
// parse the properties file
for (Map.Entry<Object, Object> e :properties.entrySet()) {
// extract the name of the object (poweroff or poweron)
String name = name((String)e.getKey());
// extract the name of the property to be set (timeout, host etc.)
String property = property((String)e.getKey());
// get the object where to set the outcome
Command command = commands.get(name);
// create the object if it wasn't already created
// and add it to the map
if (command == null) {
command = new Command();
commands.put(name, command);
}
// set the value of the given property on the corresponding object
setValue(Command.class, command, property, e.getValue());
}
System.out.println(commands);
}
static String name(String input) {
return input.split("\\.")[1];
}
static String property(String input) {
return input.split("\\.")[2];
}
static void setValue(Class<?> clazz, Object object, String propertyName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(propertyName);
field.setAccessible(true);
field.set(object, value);
}
static class Command {
String name;
String host;
String user;
String password;
String port;
String timeout;
String command;
#Override
public String toString() {
return name + " " + host + " " + user + " " + password + " " + port + " " + timeout + " " + command;
}
}
Output: {power_off=Power off host.com user password 22 10000 power off command, power_on=Power on host.com user password 22 10000 power on command}
Create a class called
public class MyProperties{
private String key;
private String value;
//get/set() methods of key/value OR Create Constructor with Varaibles
}
Now Write this logic
private List<MyProperties> createPropertyList(){
Properties proObj = new Properties();
proObj.load(new FileInputStream("PathOfPropertiesFile"));
List<MyProperties> propertyList = new ArrayList<MyProperties>();
for(String propertyKey: proObj.stringPropertyNames()) {
MyProperties myProperties = new MyProperties();
myProperties.setKey(propertyKey);
myProperties.setValue(properties.getProperty(propertyKey));
propertyList.add(myProperties);
}
return propertyList;
}
How can I, using ANTLR, populate a class of mine while I'm parsing the input message?
For example, if my input message is: name = Paul AND age = 16 AND country = china;
While I'm parsing this message, can I perform, in the Grammar file, something like:
Person p = new Person();
p.setName("Paul");
p.setAge("16");
p.setCountry("china");
Where Person.java is a class that I built. Or this can only be made in the main Java class where I print the AST?
If you want to create instance of your class from name = Paul AND age = 16 AND country = china that kind of script, then you could create yourself method
public <T> T builder(Class<T> clazz, String line)
throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
T instance = clazz.newInstance();
String[] exps = line.split("AND");
for (String exp : exps) {
String[] tokens = exp.split("=", 2);
// TODO check if token has length==2
tokens[0] = tokens[0].trim();
tokens[1] = tokens[1].trim();
String methodName = "set"
+ (("" + tokens[0].charAt(0)).toUpperCase())
+ tokens[0].substring(1);
Method m1 = instance.getClass().getMethod(methodName, String.class);
m1.invoke(instance, tokens[1]);
}
return instance;
}
and when you call it builder(Person.class,"name = Paul AND age = 16 AND country = china") you will get instance of Person class with populated fields name, age and country.
Is that what you are looking for?
How it will print welcome using following System.out.println.
Generated will give ac. But how should I make it as welcome (that ia ac value not "ac")
public class BrowserSample {
public static void main(String[] args) {
String generated = "ac";
String ac = "welcome";
System.out.println("value from generated is = " + generated);
}
}
ok After a brief experiment here is the solution you want
String generated = "ac";
String ac = "welcome"; // declare as member of class
String s = (String) getClass().getDeclaredField(generated).get(this);
s will contain welcome
What about a map, key-value pair.
Map<String,String> map = new HashMap<>();
String generated = "ac";
map.put("ac","welcome")
System.out.println("value from generated is = "+map.get("ac"));
And what you are expecting that is not possible and also meaningless.
I need to get private fields from one class and set them to another class.
This code works perfectly well for test Integer fields (100500 value gets written):
//get objects, class firs...
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, new Integer(100500));
}
Nontheless, when I switch to undefined type (the fields are of DIFFERENT types: Dates, Integers, Strings...
Eg class one has Date and class two has Date, I need to copy one value from another, but next field is going to be String in both classes)
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1);
}
I receive an IllegalArgumentException, e.g. I am not really able to get the values from one class and set it into another.
Please, dear community, give me a hint - what am I doing wrong?
to me, it looks like you hand over the field-reference instead of the field-value:
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1.get(app1)); //or whatever object field1 is from
}
though i would not do it that way because order is a fragile thing...
you could use beanutils to copy your beans, if it is, what you want to achieve
This should suit your needs:
public static <T> void copyDeclaredFields(T from, T to) throws Exception {
Class<?> clazz = from.getClass();
if (!clazz.equals(to.getClass())) {
throw new IllegalArgumentException();
}
for (Field field : clazz.getDeclaredFields()) {
Object value = field.get(from);
field.set(to, value);
}
}
To call:
Item item1 = new Item();
// item1.set...
Item item2 = new Item();
copyDeclaredFields(item1, item2);
Your error seems to be related to the fact that you are trying to set Field1 as parameter of Field, instead of the value of Field1.
field.set(app, field1);
should instead be
field.set(app, field1.get(app1));
Take a look at a small working example;
If you change
fieldDest.set(destination, fieldSrc.get(source));
to
fieldDest.set(destination, fieldSrc);
you will get the same error of this question.
Hope that helps.
Code of the example:
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
Source source = new Source();
Destination destination = new Destination();
Class sourceClassObject = source.getClass();
Class destClassObject = destination.getClass();
Field[] sourceFields = sourceClassObject.getDeclaredFields();
Field[] destFields = destClassObject.getDeclaredFields();
for (Field fieldSrc : sourceFields) {
int mod = fieldSrc.getModifiers(); // get modifiers
System.out.print("Source Field: " + Modifier.toString(mod) + " "
+ fieldSrc.getType() + " " + fieldSrc.getName());
fieldSrc.setAccessible(true);
System.out.println(" [" + fieldSrc.get(source) + "]");
for (Field fieldDest : destFields){
if (fieldDest.getType().equals(fieldSrc.getType()) &&
fieldDest.getName().equals(fieldSrc.getName())){
fieldDest.setAccessible(true);
fieldDest.set(destination, fieldSrc.get(source));
}
}
}
destination.printValues();
}
static class Source{
public Source(){
strField = "This is a String";
intField = 42;
dateField = new Date();
}
private String strField;
private Integer intField;
private Date dateField;
}
static class Destination{
private String strField;
private Integer intField;
private Date dateField;
public void printValues(){
System.out.println("Destination Field values: ");
System.out.println("strField: " + strField);
System.out.println("intField: " + intField);
System.out.println("dateField: " + dateField);
}
}
}