access java object variable dynamically - java

I'm very new to Java and Android development.
I have a case where I need to populate an object with data from an XML document. Some of the node names in the XML are not standardised in any way, so I have created a HashMap where the key is the node name, and the value is the variable it needs to be assigned to.
In PHP the code would look something like (in basic terms):
$array = new Array("somenodename" => "firstname", "someothernodename" => "lastname");
$object = new Person();
$object->{$array['somenodename']} = "Whatever the XML node value was";
In Java I have gotten as far as:
From the object I need to populate:
public String firstname;
public String lastname;
public static Map getHashMap(){
Map<String, String> map = new HashMap<String, String>();
map.put("somenodename", "firstname");
map.put("someothernodename", "lastname");
return map;
}
From the class populating the object assuming the somenode and someothernode are dymanic:
Person person;
Map personMap = person.getHashMap();
if( personMap.containsKey("somenodename") ){
person.[personMap.get("somenodename")] = "James";
}
if( personMap.containsKey("someothernodename") ){
person.[personMap.get("someothernodename")] = "Bond";
}
Is there anyway of assigning a value to an class variable where the variable name is... variable?

It's called Reflection
Assume you want to call the method myMethod(String s) from Person:
Person p = new Person();
Class<Person> clazz = p.getClass();
Method m = clazz.getMethod("myMethod", String.class);
m.invoke(p, "my string argument");

Related

Get and change hashmapvalues [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have an HashMap myHashMap, like this:
public static void main(String[] args) {
HashMap<String, UserContact> myHashMap = new HashMap<String, UserContact>(); // first string = username
fillHasmap(myHashMap); // a method to fill my hashmap
HashMap<String, String> usernameAndType = new HashMap<String, String>(); // username , userType
fillUsername(usernameAndType);
myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))); // does not work.
}
public static void fillHasmap(HashMap<String, UserContact> myHashMap) {
for(int i = 0; i<5; i++) {
UserContact single = new UserContact();
String username = "stack" + i;
single.setUsername(username);
single.setUserType("Client");
single.setUserEmail("temp" + i + "#drop.me");
myHashMap.put(username, single);
}
}
public static void fillUsername(HashMap<String, String> usernameAndType) {
String[] userType = {"Client","Business"};
for(int i = 0; i<5; i++) {
String username = "stack" + i;
Random r = new Random();
int a = r.nextInt(2);
usernameAndType.put(username, usertype[a]);
}
}
The UserContact class is this one:
public class UserContact{
private String username;
private String userType;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email= email;
}
}
I want to change all the userType of my UserContact using the one present in the usernameAndType hashmap.
To do It I have used:
myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p)));
But It doensn't work, because I think that without saving it in another hashmap is pointless. So I have tried something like this but I can't compile it because I have an error:
myHashMap= myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))).collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new);
Cannot invoke collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new) on the primitive type void
I kwon that I can pass the usernameAndType Hashmap to the method fillHasmap and get the element directly using it, but there is really another way to do it?
If I understand the contents of the two maps correctly, I think the following works as an update in place:
myHashMap
.entrySet()
.forEach(entry ->
entry.getValue().setUserType(usernameAndType.get(entry.getKey())));
Even easier would be to use the following form:
myHashMap
.forEach((key, value) ->
value.setUserType(usernameAndType.get(key)));
Your basic requirement is to construct a new HashMap? Or to mutate the values present in the original HashMap?
If it is to mutate the values present in original HashMap.
myHashMap.values().stream().forEach(val -> val.setUserType(usernameAndType.get(val.getUserName())));
If you need to construct another HashMap with the updated one (Why?!), simply you can do this after the previous step.
Map<String,UserContact> myHashMapNew = new HashMap<>(myHashMap);
There are many things wrong with the code :
First (your code) :
myHashMap= myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))).collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new);
you are calling collect on a non stream. I wont point out the mistakes here but according to your implementation (at least how you'r trying to do it ). This should have been enough to change / mutate the value of the original map without having need to create a new one.
myHashMap.entrySet().forEach(p -> p.getValue().setUserType("someuserType"));
here the p is a Map.Entry (key, value ), and the value is a UserContact so p.getValue() = UserContact then call a setter to the object
Answer : May be for a new map, you wanna do something like this:
Map<String,String> newMap = myHashMap.entrySet()
.stream()
.map(Map.Entry::getValue)
.collect(Collectors.toMap(UserContact::getUsername,UserContact::getUserType));
Shortcut to the above example would be:
Map<String,String> newMap2 = myHashMap.values().stream()
.collect(Collectors.toMap(UserContact::getUsername,UserContact::getUserType))
Assuming that you don't have getters for the userType, try this to create the usernameType hashMap. If you want to modify the original hash map see my second example.
this streams the entrySet of your first map.
creates a new map with the key and the value being the userType.
remember the getValue() returns a UserContact object so you need to dereference it to get the userType
Map<String,String> usernameAndType = myHashMap
.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey, e->e.getValue().userType));
If you have getters for your fields, the you can change
e->e.getValue().userType to
e->e.getValue().getUserType() or whatever you named it.
To use the information in the usernameAndType hash map to modify the objects in myHashMap, do the following:
NOTE: You should use a loop to do this because it is considered poor technique to modify external objects from within a stream.
for (Entry<String, UserContact> e : myHashMap.entrySet()) {
UserContact uc = e.getValue();
uc.setUserType(usernameAndType.get(e.getKey());
}

Merge two different object lists into one with a shared id field

I have two different objects list like those:
public class Person {
private int id;
private String name;
private String surname;
}
public class Name {
private int id;
private String name;
}
My Person list doesn't have the field name filled. I need to merge it with the Name list matching the field id.
Question: How is the best way to do this with Java 8 streams?
First, using a Map is better for accessing the Name objects, so using streams here is a solution:
List<Person> personList = ...
List<Name> nameList = ...
Map<Integer,String> nameMap = nameList.stream()
.collect(Collectors.toMap(Name::getId,Name::getName));
personList.forEach(person -> person.setName(nameMap.getOrDefault(person.getId(), "")));
You can do it like this:
Map<Integer, String> map = names.stream().collect(Collectors.toMap(o -> o.id, o -> o.name));
for (Person person : persons) {
person.name = map.getOrDefault(person.id, "");
}
Assuming names is your list of Names and persons is your list of Person, also if the person id is not found the default name is the empty string.

How to transform list of objects into one row object in java

I have a class A having private members like below.
class A {
String type;
}
The above class will come as list objects List . Now i have Another class B
Class B {
String type1;
String type2;
String type3;
String type4;
String type5;
String type6;
String type7;
String type8;
}
So Now How i have to iterate through List and get the (type(s)) data one by one and then put it into Class B as single object like first one will go to Type1 , second one ---> type2, third one--- > type3 ....., so on.
Note : There will be only 8 types in class A as a list . so we will have exactly 8 types in Class B and i have thought on reflection so please tell how do i use it, if this is the only option.
Jasper supports Map, so I would suggest you can store the values in a SortedMap, such as a TreeMap rather than a class with public variables.
Then you would add your type names like this:
Map<String, String> b = new TreeMap<>();
b.put("type1", "Foo");
b.put("type2", "Bar");
b.put("type3", "Baz");
...
Or if you're populating from a list of A:
List<A> list = ...;
Map<String, String> b = new TreeMap<>();
for (int i = 0; i < list.size(); i++) {
b.put("type" + (i + 1), list.get(i).type;
}
To iterate over all the names in the map, you could then use:
for (Map.Entry<String, String> entry: b.entrySet()) {
String key = entry.key();
String value = entry.value();
System.out.println(key + " = " + value);
}
If you can change the class B as:
class B
{
String[] types;
}
Then we can do:
int i = 0;
for(A aObject:aList){
bObject.types[i] = aObject.type;
}
Else we can add all types like this:
bObject.type1 = aList.get(0).type;
bObject.type2 = aList.get(1).type;
and so on.

Storing a new object as the value of a hashmap?

I am trying to find a way to store a new instance of a class as the value in a Java hashmap. The idea was given to me by a Java instructor in order to create a data storage structure that could be used to for a program I am working on.
The idea he recommended to me was to use a hashmap that stored the name of a computer as the key and the value would be a new instance of the class InfoStor.class. InfoStor contains methods such as getName(), setName(), getMemory()...
I have the class and the method pretty much setup for a basic test to see if it would work or not. The problem I am running into is I cannot figure out how to use the methods inside of InfoStor once I have created a new entry in the hashmap.
This is the code I have so far;
VMware.class
import java.util.HashMap;
public class VMware {
public static void main(String[] args) {
HashMap <String, Object> mapper = new HashMap();
mapper.put("NS01", new InfoStor("NS01"));
//mapper.get("NS01").
}
}
InfoStor.class
public class InfoStor {
private String vmName;
private String platform;
private Integer memory;
public InfoStor (String name) {
vmName = name;
}
String getName(){
return vmName;
}
void setPlatform(String p){
platform = p;
}
String getPlatform(){
return platform;
}
void setMemory(Integer m){
memory = m;
}
Integer getMemory(){
return memory;
}
}
What I am trying to accomplish is something like this (basic idea).
Object var = mapper.get("NS01");
System.out.println(var.getMemory());
Am I going about this the wrong way? Any help is appreciated thanks.
The problem is that your code only specifies that the values in the map are Object. You know more than that, so tell the compiler that information:
HashMap<String, InfoStor> mapper = new HashMap<String, InfoStor>();
mapper.put("NS01", new InfoStor("NS01"));
...
InfoStor value = mapper.get("NS01");
Integer memory = value.getMemory();
Note that it's generally though not always better to use interfaces for the variable types - and you can use the diamond operator for the constructor call, letting the compiler use type inference to fill in the type arguments:
Map<String, InfoStor> mapper = new HashMap<>();
mapper.put("NS01", new InfoStor("NS01"));
...
InfoStor value = mapper.get("NS01");
Integer memory = value.getMemory();
If you declare your hashmap like so:
HashMap<String, InfoStor> mapper = new HashMap<String, InfoStor>();
Then when you get an object out of the mapper, it will be an instance of InfoStor (you won't need to cast it or worry about a class cast exception because it's not the rist class.)
So:
InfoStor myStor = mapper.get("somekey");
myStor.getMemory(); // this will work
Otherwise, if you stick with the HashMap<String, Object> you used in your original code, you'll need to cast it before you call the method:
Object obj = mapper.get("somekey");
((InfoStor)obj).getMemory(); // cast is required
obj.getMemory(); // this will not compile
You should read up on Java generics.
Make use of the generics added to java. They help with both compile-time type-checking and they make the casts unnecessary.
HashMap <String, Object> mapper = new HashMap();
//you will be able to retrieve an object and then cast it to your InfoStore
InforStore isN01 = (InfoStore)mapper.get("N01");
//this will unfortunately be accepted, even thought it's a bug
mapper.put("N02", new Integer(0));
________________________
HashMap <String, InfoStore> mapper = new HashMap();
//you will be able to retrieve an object and then cast it to your InfoStore
InforStore isN01 = mapper.get("N01"); //no cast
Youre on the right track...
Initialise the map as:
HashMap <String, InfoStor> mapper = new HashMap<String, InfoStor>();
Then after adding objects to the map retrieve them with:
InfoStor var = mapper.get("NS01");
System.out.println(var.getMemory());
you can cook something by using array...for example if you can store objects in arrays then use that idea to achieve it in hash map...i dont knw how you design but i once got stuck in that and made through like this
example...
class princess{
int age;
public princess(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
}
public class hashmaptest {
public static void main(String[] args) {
princess[] p=new princess[10];
HashMap scores = new HashMap();
scores.put("a",new princess(6));
scores.put("b",new princess(7));
p[0]=(princess)scores.get("a");
System.out.println(p[0].getAge());
p[0]=null;
p[0]=(princess)scores.get("b");
System.out.println(p[0].getAge());
}
}

Comparing and deleting similar strings within a vector

JAVA: First off, Thanks so much for taking the time to look at my question; your help is EXTREMELY appreciated!
So, the problem is i have a Vector of Objects in Java and each object has a name(String). But, i have tons of objects that are repeated, and the ones that are repeated are always directly after the Object they repeat. Also the number of repeats ranges from 1-10(So frustrating) its completely random.
How would i go about deleting the repeats, I thought about comparing each objects name with the next in the vector and deleting all of the ones that match but that gave me tons of problems. Thank you SO much for your help in advance!
-Dylan
EDIT: Just to make sure you understand the kind of repetition i'm talking about ive added this.
Vector
---Object1(String name = "hi") --> Remove This one.
---Object2(String name = "hi")
---Object3(string name = "bob")
End Vector
Edit 2: add Code
public class Vector
{
public static void main(String args[])
{
Person person1 = new Person("jane");
Person person2 = new Person("jane");
Person person3 = new Person("bob");
Person person4 = new Person("shelly");
Vector<Person> vectorObject = new Vector<Person>
vectorObject.add(person1);
vectorObject.add(person2);
vectorObject.add(person3);
vectorObject.add(person4);
}
}
class Person
{
String name = null;
String bDay = null;
String color = null;
public Person(String name)
{
this.name = name;
}
}
It seems you should use a different data structure.
You may want to use a Set instead of a Vector. Sets do not contain duplicate elements. You've to override equals(Object) method.
Or use a Map with the name property as key value and store the corresponding Person object as value.
In both cases you prevent duplicates rather then deleting them afterwards.
Person person1 = new Person("jane");
Person person2 = new Person("jane");
Person person3 = new Person("bob");
Person person4 = new Person("shelly");
Map<String, Person> nameToPerson = new HashMap<>();
nameToPerson.add(person1.name, person1);
nameToPerson.add(person2.name, person2);
nameToPerson.add(person3.name, person3);
nameToPerson.add(person4.name, person4);
Collection<Person> noDuplicatesHere = map.values();
Well, I don't know which language are you using, so I will give you an algorithm in JavaScript:
var newvector=new Array();
var lastName;
for(var i=0;i<vector.length;i++){
if(!lastName || vector[i].name!=lastName){
lastName=vector[i].name;
newvector.push(vector[i]);
}
}
The problem is that this way a new vector is created, and if the original one is huge maybe you will have memory problems.
Here is your first problem:
class Person
{
String name = null;
String bDay = null;
String color = null;
public Person(String name)
{
name = this.name;
}
}
it should be:
class Person
{
String name = null;
String bDay = null;
String color = null;
public Person(String name)
{
this.name = name;
}
}
Here is more info on the this keyword:
http://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html
Your second problem is: I'm guessing you are trying to create a Vector, java.util.Vector to be exact. If you create a new instance of Vector inside of a class called vector, it will create a new instance of itself, not of java.util.Vector. You can either rename the class or you can just do:
java.util.Vector<Person> vector = new java.util.Vector<Person>();
if you want to compare 2 string values use:
String name = "John";
String name2 = "Joe";
if(name.equalsIgnoreCase(name2))
System.out.println("They match!");
You can also just use equals() if you want an exact match.
Hope this helped!

Categories

Resources