Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 926
TheDude Avatar asked Dec 07 '25 14:12

TheDude


2 Answers

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.

like image 137
Lars Christian Jensen Avatar answered Dec 09 '25 02:12

Lars Christian Jensen


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);
like image 37
cameron1024 Avatar answered Dec 09 '25 03:12

cameron1024



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!