0

I have a few items from various classes, I would like to write a method taking generic object (Object is the superclass of all other classes)

  • verify items all have getId() method
  • then collect the getId() value.

Note the object could really by anything - it cannot be bounded

I tried something like

  String getObjectId(Object item) throws Exception {
    // If the getId() method is not implemented, throw exception
    if (Arrays.stream(item.getClass().getMethods())
        .filter(method -> "getId".equals(method.getName()))
        .findFirst()
        .isEmpty()) {
      throw new Exception(...);
    }

    return item.getId();
  }

The problem is the compiler ignores this verification - i always get this error even though I just verified it has the method


cannot find symbol
  return item.getId();
                ^

How can I call a method in this case?

Jenny R
  • 3
  • 1
  • have you checked the Object class whether or not it has a 'getId()' method? your return statement isn't going through the getClass() and all of that. it just goes looking for that method in the Object class, since that is what item is declared to be – Stultuske Nov 30 '22 at 07:32
  • Proper way would be using an interface enforcing the presence of getId(). – Christoph Dahlen Nov 30 '22 at 07:33
  • You can't call `item.getId()` on `Object` just like this. If yousing reflection you'd need to use `Method.invoke(item)` to call the method you've found. But reflection doesn't seem like a good solution here, can't you add a common interface to those classes that exposes the `getId()` method? That way you'd probably not even need that `getObjectId()` method in the first place. – Thomas Nov 30 '22 at 07:34
  • I believe it doesn't https://developer.classpath.org/doc/java/lang/Object-source.html Hmmm a good point though. Maybe I can rename getId() by an identity function that exists in Object – Jenny R Nov 30 '22 at 07:36
  • @JennyR in that case, you change the functionality of your code, and it won't make sense to have it anymore – Stultuske Nov 30 '22 at 07:38
  • 1
    Hi Bishan, thanks for the suggestion! The incoming items are from a large variety of classes, many of them already had interface or parent classes, not easy to just just add an interface for all. – Jenny R Nov 30 '22 at 07:43
  • @JennyR Classes can implement multiple interfaces. I wouldn't be afraid of changing a lot of classes if it is the correct thing to do. – rghome Nov 30 '22 at 08:02

2 Answers2

3

when you call item.getId(); java do not know what is the exact type of your object and as a result it does not know what is your object type. Even you checked it previously using reflection.

  1. If you want to call getId method from object, this snippet can help you:
Method getIdMethod = item.getClass().getMethod("getId");
Object result = getIdMethod.invoke(item);
return result == null? null: result.toString();
  1. If all of your objects has getId() method, you can change your code without using reflection:
public interface Identifiable {
   String getId();

   void setId(String value);
}

class A implements Identifiable {
...
}

class B implements Identifiable {

}

Example of usage:

Collection<? extends Identifiable> coll = new ArrayList<>();
...
coll.stream().map(Identifiable::getId).collect(Collectors.toList());
Rustam
  • 378
  • 2
  • 6
0

Too long for comment, so it'll be an answer.

In your case, what I would do, as others have already suggested, is use base types.

Say you have the following base types (interfaces, abstract classes):

IMyInterface, MyAbstractClass, IGetInfo.

package com.me;

public class MyWorker implements IGetInfo {

    public String getObjectInfo() {
        return "MyWorker";
    }    

    public String getObjectInfo(IGetInfo x) {
        return x.getObjectInfo();
    }

    
    public String getObjectInfo(IMyInterface x) {
        return x.getId();
    }

    // and so on

}

This makes your intent clear in the code. It's not as DRY as some people would like it, but it definitely makes your code easier to understand and you avoid issues when having to faff about with objects which may or may not have certain expected methods/properties.

Another solution would be using reflection to inspect an object, to determine whether or not it implements a given interface/class and then act upon it, or throw an exception. That would allow you to continue using Object for your method, but reflection can get somewhat complicated and hard to read after a while.

SimonC
  • 1,547
  • 1
  • 19
  • 43
  • OP already mentioned in the comments adding an interface is not an option. – Stultuske Nov 30 '22 at 08:01
  • OP said that interfaces are already in place, so that adding further ones isn't an option. This answer suggests using the existing interfaces and overloaded methods - or reflection if need be – SimonC Nov 30 '22 at 08:13
  • yes, but if all the types provided a getId(), the check the OP runs wouldn't even be necessary – Stultuske Nov 30 '22 at 08:17
  • If I understood OP correctly, all the (valid) types passed to the method provide getInfo(), so that only unsupported types don't. This IMO is another argument for overloaded methods, depending on the underlying type. A further method inspecting the object with reflection is not out of the question though – SimonC Nov 30 '22 at 08:19
  • My score is too low to upvote. but thanks for sharing the great idea! – Jenny R Nov 30 '22 at 08:20
  • using interface is definitely safer - but I don't wanna change too many code from clients, therefore picked the other method due to realistic concerns, opposite to craftsmanship – Jenny R Nov 30 '22 at 08:21