Copy fields and value of an object to a Map - java

I want to copy fields from a complex object- that is an object which contains other objects.
Now it copies wrapper classes with no issue but how do i copy the fields and values of the subclass
code
public Map<String, Object> getValueMapFromInsuranceVehicle(Long insuranceId) throws InvocationTargetException, IllegalAccessException {
InsurancePolicy insurance = repository.findById(insuranceId).get();
Method[] methods = insurance.getInsuranceVehicle().getClass().getMethods();
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get")) {
Object value = m.invoke(insurance.getInsuranceVehicle());
map.put(m.getName().substring(3), value);
}
}
// add other fields specific to our needs like currentYear
return map;
}
From the code above it copies insuranceVehicle fields correctly, But i would like to copy the whole InsurancePolicy object and put the values in a map.
when i try it with InsurancePolicy i get exception cannot convert InsurancaCalculation into String,
my Insurance policy object looks like this
class InsurancePolicy {
#OneToOne
private Person person;
#OneToOne
private Vehicle vehicle;
#OneToOne
private InsurancePolicyStatus status;
private LocalDate policyStart = LocalDate.now().plusDays(1);
private LocalDate policyEnd = policyStart.plusYears(1).minusDays(1);
private boolean policy_AC = true;
private boolean policy_OC = true;
private boolean policy_ASS;
private boolean policy_NNW;
private String vehicleUsageType;
InsuranceCalculation calculation
#Embedded
private InsuranceVehicle insuranceVehicle;
#Embedded
private InsuranceCustomer customer;
private String coownerHowMany;
private String abroad;
}
Finally my question how can i improve my method getValueMapFromInsuranceVehicle() to get more fields copied ?
basically how to make this code below to work
public Map<String, Object> getValueMapFromInsuranceVehicle(Long insuranceId) throws InvocationTargetException, IllegalAccessException {
InsurancePolicy insurance = repository.findById(insuranceId).get();
Method[] methods = insurance.getClass().getMethods(); // insurance instead of vehicle
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get")) {
Object value = m.invoke(insurance); // insurance instead of insurancevehicle
map.put(m.getName().substring(3), value);
}
}
// add other fields specific to our needs like currentYear
return map;
}

To get the methods of other objects in InsurancePolicy you could use your same code but add some checks for if the object is InsuranceCustomer, InsuranceVehicle, or InsuranceCalculation by using instanceOf and if it is use the same code just with Method[] methods = insurance.getClass().getMethods(); changed to the objects class. I would recommend separating your code into more methods so you can use recursion.

Related

Java 8 - Map between class to one of its function

I have multiple types of objects, I'd like to generalise the 'id' of the objects in a way that will dynamically change what field is selected as the id.
Example
public class ObjectA{
//Attribute name attA
private String attA;
.... More attributes
public String getAttA(){
return attA
}
.....More getters/setters
}
public class ObjectB{
//Attribute named attB
private String attB;
.... More attributes
public String getAttB(){
return attB
}
.... More getters and setters
}
Id like to be able to run something like this:
Map<????, ????> customIdMap = new HashMap<>();
//We decide that ObjectA main attribute is AttA
customIdMap.add(ObjectA.class, ObjectA::getAttA);
//We decide that ObjectB main attribute is AttB
customIdMap.add(ObjectB.class, ObjectB::getAttB);
Then I'll be able to have a list of general objects and ill be able to retrieve their ids from the map if it is a known object with:
public String getCustomId(Object object){
if(customIdMap.contains(object.getClass()){
//Parameters are messed up, but this is the general idea of how
//i thought this would look
return customIdMap.get(object.getClass()).apply(object);
}
}
The code above does not run since getAttA is a call to a none static method in a static context so i assume this maybe should be wrapped in some kind of generic object.
Can it be done?
Preferably you change ObjectA and ObjectB to have a common interface. If that's not possible you can put them into a map like this:
Map<Class<? extends Object>, Function<Object, String>> map = new HashMap<>();
map.put(ObjectA.class, a -> ((ObjectA) a).getAttA());
map.put(ObjectB.class, b -> ((ObjectB) b).getAttB());
EDIT:
Or if you would like to encapsulate it into a typesafe heterogeneous container:
public static class ToIdMap {
private final Map<Class<?>, Function<Object, String>> map = new HashMap<>();
public <X> void put(Class<X> clazz, Function<X, String> func) {
map.put(clazz, (Function<Object, String>) func);
}
public String toIdString(Object o) {
return map.get(o.getClass()).apply(o);
}
}
EDIT2: Note that neither of these solutions work for subclasses, but it could be supported by traversing the class hierarchy in toIdString.
Your wording is a bit unclear, but I assume you want to get the ID of an object, even when they are different classes. This is the problem that interfaces solve.
You can create an interface, with one method called getId(), which will return the id. Then, you can just call getId() on any type of object with an id.
For example:
public interface Identifiable {
String getId();
}
public class ObjectA implements Identifiable {
// same for ObjectB
#Override
public String getId() {
return id;
}
}
Then, in your code:
Identifiable i1 = new ObjectA();
Identifiable i2 = new ObjectB();
System.out.println(i1.getId());
System.out.println(i2.getId());
EDIT:
It still looks like an interface is the cleanest way of solving your problem. For completeness, the following will work:
Map<Class, Function<?, String> map = new HashMap<>();
map.put(Object1.class, (Object1 o) -> o.getAttrA); // repeat for ObjectB
It can then be called with:
if (obj instanceof Object1) return map.get(Object1.class).apply((ObjectA) obj);
Ended up doing this weird solution:
class Mapping<T> {
private Function<T, String> idFunc;
public Mapping(Function<T, String> idFunc) {
this.idFunc = idFunc;
}
public String apply(T obj) {
return idFunc.apply(obj);
}
}
}
private Map<Class, Mapping> mappings = new HashMap<>();
mappings.put(ObjectA.class, new Mapping<>(ObjectA::getAttA);
mappings.put(ObjectB.class, new Mapping<>(ObjectB::getAttB);
public String getObjectID(Object object){
String id = null;
if(mappings.containsKey(object.getClass())){
id = mappings.get(object.getClass()).apply(object);
}
return id;
}

Java : How to create map using the class attributes?

I am trying to create a map from all the attributes that a class have.My class looks like :
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
}
Now I have collected all the methods that the class has as :
Field[] fields = this.getClass().getDeclaredFields();
Now , I am trying to create a Map out of it where keys are the values of the fields and the values are the name of the fields. Example :
Map<46,battery> ...etc
Is there a way to do it?
The attribute values for the above mentioned class were generated by mapping to properties file and by using spring annotation #ConfigurationProperties. Now I need to create the Map but keys the values of the attributes. I tried to use reflect. However did not find a way to get the value of the fields.
Thanks
You can use Introspector class.
public Map<Object, String> populateMap(final Object o) throws Exception {
Map<Object, String> result = new HashMap<>();
for (PropertyDescriptor pd : Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors()) {
String fieldName = pd.getName();
if("class".equals(fieldName) continue;
Object value = pd.getReadMethod().invoke(o);
result.put(value, fieldName);
}
return result;
}
You can call the above method, passing your class as argument.
MyInventory mi = new MyInventory();
// Sets the properties of mi
mi.setXXX...
// Populates map
populateMap(mi);
Map<Integer, String> map() throws IllegalArgumentException, IllegalAccessException {
Field[] fields = getClass().getDeclaredFields();
Map<Integer,String> map = new HashMap<>();
for (Field field : fields) {
map.put(field.getInt(this), field.getName());
}
return map;
}
Of course it will not map properly if different fields have the same value.
I think, you can have getter method in your class
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
public int getBattery()
{
return battery;
}
//and other getter
}
and then you can populate your map as
map.put(inventory.getBattery(),"battery");
Because, when you have value, which means you know what is the type for which you are populating map.
You can use json parser. For example jackson:
import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(mapper.writeValueAsString(fooOject), HashMap.class);

Java self-reflection

It's rather strange, but I want to call self method.
This is my abstract class
public abstract class AbstractMapper {
public AbstractMapper(Map<String, String> map) {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field: fields) {
if (field.getAnnotation(Column.class) != null) {
String fName = field.getName();
String rsName = field.getAnnotation(Column.class).name();
StringBuilder sb = new StringBuilder("set")
.append(Character.toUpperCase(fName.charAt(0)))
.append(fName.substring(1));
String mName = sb.toString();
// this.invoke(mName, map.get(fName)); <-- What should I put this here?
}
}
}
public Result getCalculatedValues() {
return xxxx;
}
}
And this is my class
public class NewMachine extends AbstractMapper{
#column(name = machine)
private String machine;
#column(name = temperature)
private Double temperature;
// normal get/set methods
}
Now, my goal is that AbstractMapper constructor iterates through all fields with columns, and invoke all of its respective setters.
in this case, I can pass something like
Map<String, String> map = SomeClass.SomeMethod();
NewMachine m = new NewMachine(map);
Result r = m.getCalculatedValues();
Thank you for helping.
Try getClass().getMethod( mName, field.getType() ).invoke(this, map.get(fName) ) (and handle any possible exceptions ofc).
Additionally keep the JavaDoc on getDeclaredFields() in mind:
Returns an array of {#code Field} objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
If you have a hierarchy you'd have to get the fields of the super classes as well.

Handling meta of class (reference to properties)

I am trying to set up a small metamodel in order to reference some properties on multiple classes.
Example: Using the classes below, I'd like to store only Person.name and Person.surname in MetaManager.config. The problem is, I don't want to store the values of name and surname, but a reference to the field. By storing these references of the field, later on I can retrieve the name and surname of any instance of Person I would pass to MetaManager.getValues().
This code is similar to Metamodel API, though I am not sure whether I should use this (since Metamodel is part of persistence and this is not related to persistence). In this API the reference is made like this Person_.name using the EntityType object.
The question is, in what way can I store a reference to these properties so I can retrieve the value of these properties from an instance later on?
The code below gives a sketch of what I'm trying to accomplish. As you can see, my problem is in Person.getValue() and a toString() on this reference (a reference on ssn would thus return "ssn").
interface IMetable {
Object getValue(Meta meta);
}
class Person implements IMetable {
String ssn;
String name;
String surname;
Person(String ssn, String name, String surname) {
this.ssn = ssn;
this.name = name;
this.surname = surname;
}
#Override
Object getValue(ClassMeta meta) {
// Return the value of the (by meta) referenced field
return null;
}
}
class MetaManager {
Map<Class, Meta[]> config;
public Map<String, String> getValues(IMetable object) {
if(config.containsKey(object.class)) {
ClassMeta[] metamodel = config.get(object.class);
Map<String, String> values = new HashMap();
for(Meta meta : metamodel) {
values.put(meta.toString(), object.getValue(meta).toString());
}
return values;
}
else {
throw new Exception("This class has not been configurated.");
}
}
}
You appear to be trying to recreate the reflection API.
Why wouldn't you just implement MetaManager like this:
public class MetaManager
{
public Map<String, Object> getValues(Object object)
{
Map<String, Object> values = new HashMap<String, Object>();
for (Field field : object.getClass().getFields())
{
boolean wasAccessible = field.isAccessible();
try
{
field.setAccessible(true);
values.put(field.getName(), field.get(object));
}
finally
{
field.setAccessible(wasAccessible);
}
}
return values;
}
}
If you need a subset of fields then use an Annotation to mark those fields and then check for that Annotation before adding it to the values map.

Java Reflection - listing properties (getters & setters) of a class

public class foo
{
private String _name;
private String _bar;
public String getName() {
return _name;
}
public void setName(String name) {
_name = name;
}
public String getBar() {
return _bar;
}
public void setBarn(String bar) {
_bar = bar;
}
}
If I have the above class can I use reflection to list the properties defined by the getters and setters? I've tried the method below but it doesn't work, Field[] fields is left empty. I know I can do this in .Net but Java is a very different animal. Am I barking up the wrong tree altogether?
private HashMap<String, String> getHashMap(Object obj) {
HashMap<String, String> map = new HashMap<String, String>();
Class<?> cls = obj.getClass();
Field fields[] = cls.getFields();
for(Field f : fields) {
String name = f.getName();
String value = f.get(obj).toString();
map.put(name, value);
}
return map;
}
Also setters and getters maybe evil, should I just drop this?
Maybe use cls.getDeclaredFields instead ? (And f.setAccessible(true) before get private field).
If you want getter and setter you have to get method by getDeclaredMethods. Then I suggest using BeanUtils instead of writing your own reflection logic :) (IMHO less convenient is java.beans.Introspector).
Use the Introspector class. Obtain the BeanInfo and use getPropertyDescriptors() method. That should get you on the way.
You can do something like this:
List<Method> methods = Arrays.asList(getClass().getDeclaredMethods());
for (Method m : methods)
{
String name = m.getName();
if (name.startsWith("get") || name.startsWith("is"))
{
// Do something with the getter method
} else if (name.startsWith("set"))
{
// Do something with the setter method
}
}

Categories

Resources