0

I want to possibly use Java Reflection to set some data at RunTime. My problem is I can't figure out how do I get sub-classes information and use as a part of reflection.

I want to use Reflection to keep it generic functionality for future flexibility.

Java Structure - Class & Fields (field data type in brackets) following in bullets. Setter / Getter methods for each field is present. This is sample representation.

Restaurant
  - RestaurantId (long)
  - RestaurantName (String)
  - RestaurantCity (String)
  - Employee (Employee object)
  - Menu (Menu object)

   Employee
     - EmployeeId (long)
     - EmployeeName (String)

   Menu
     - MenuId (long)
     - MenuItem (String)
     - MenuCategory (String)
     - MenuIngredients (Ingredients object)

       Ingredients
         - IngredientId (long)
         - IngredientName (String)

As we can see I have multiple level of object structure. So Restaurant as the top most object, then within Restaurant there is object of Employee and Menu and within Menu object there is a Ingredients object.

Requirements

I will get class name and field (method name) to set the value. E.g. I will get something like Class = Restaurant & Field Method = setRestaurantCity and value to set in the City. I may also get Class = Menu & Field Method = setMenuItem or let's say Class = Ingredients & Field Method = setIngredientName and respective values for them.

I have provided sample java code with which I am trying to test. As we could see in java code that it works fine for setting value in Restaurant object. However I would like to set the data in another object which is actually two levels down to Restaurant, that is, Restaurant --> Menu --> Ingredients. for valueObject2.

I don't want to use instanceOf as that would need me to verify each and every object. As current structure is not just 2 levels but much more deeper something like going upto 5 levels down with total class objects counting upto 25 of them.

I am looking for some solution where I can match the names of the class and set respective values. So, if I get valueObject3 and respetive Class & Field is sent in future, then the solution should work.

Open for any other solution as well other than Reflection

Java Code

public static void main(String[] args) {

        try {
            Object valueObject1 = "Mumbai";
            String fromClass1 = "com.test.Restaurant";
            String fromMethod1 = "setRestaurantCity";

            Object valueObject2 = "Bread";
            String fromClass2 = "com.test.Ingredients";
            String fromMethod2 = "setIngredientName";

            Object restnt = new Restaurant();
            Class<? extends Object> clsRestnt = restnt.getClass();
            System.out.println(clsRestnt.getCanonicalName());

            Method[] toRestMethods = clsRestnt.getMethods();

            for (int i = 0; i<toRestMethods.length; i++)
            {
                System.out.println(toRestMethods[i].getName());
                if(toRestMethods[i].getName().equalsIgnoreCase(fromMethod1))
                {
                    System.out.println("Found Method " + toRestMethods[i]);
                    valueObject1 = toRestMethods[i].invoke(restnt, valueObject1);

                }
            }

        } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
  • 1
    I want to use Reflection to keep it generic functionality for future flexibility. That is a very bad reason for using reflection. You will end up happier if you achieve that goal by other means. – Kilian Foth Apr 27 '16 at 11:51
  • Surely "getting subclass information" should be done through methods the subclasses override? Or else you're wildly violating LSP and missing the whole point of a class hierarchy? – Ixrec Apr 27 '16 at 11:55
  • @KilianFoth.. I just thought that's the solution for kind of problem.. Am open for any other solution if you can suggest.. – vnkotak Apr 27 '16 at 11:56
  • @Ixrec.. I understand your points, but am not getting any other solution.. Exact requirement is that I will be getting some task to be done and corresponding value.. Now every task can be at different level in the hierarchy of the class... So I am not how else should I implement this. :( – vnkotak Apr 27 '16 at 11:59
  • @vnkotak By providing protected methods that subclasses are expected to override...? If you're saying someone has forbidden you from using something sane like protected methods, unfortunately that's not really a problem we can help with. – Ixrec Apr 27 '16 at 12:16
2

Reflection seems a very fragile and non-intuitive way to implement this. Instead I think you should be telling the objects what to do, and they will collaborate between themselves to determine this. e.g.

restaurant.switchToSpringMenu();

and the Restaurant object could swap between menu instances that it has.

Exact requirement is that I will be getting some task to be done and corresponding value.. Now every task can be at different level in the hierarchy of the class... So I am not how else should I implement this

Perhaps this could be achieved via a visitor pattern. e.g. you do something like:

restaurant.reorganise(forSummer);

where forSummer is some implementation of a task. The Restaurant object collaborates with this task object, then calls on the underlying Employee/Menu classes, which will do the same.

If you really want a more generic means of navigating these hierarchies, you could look at JXPath, which allows you to use XPath-like expressions to find objects e.g.

 (Ingredient)JXPathContext.newContext(restaurants).
         getValue("restaurant[address/zipCode='90210']/menu/ingredients[1]");
  • Is JXPath doing any sort of Marshalling?. If so, what do we gain doing marshalling vs reflection (via Apache Commons)? From my experience, marshalling/unmarshalling are expensive task in terms of resources (cpu, memory, ...) – Laiv Apr 27 '16 at 15:21
  • 1
    I assume (!) it's just using reflection, like the original questioner's code, but someone has gone through the development pain in advance. I think the XPath compilation takes some time, but I seem to remember you can do a precompilation of that. To reiterate, I don't think it's a good solution for the above, but rather I've used it when I've want to be able to specify attributes in an object hierarchy that I want to extract configurably. And for unit tests occasionally. – Brian Agnew Apr 27 '16 at 16:02
  • I will add JXPath to my list of "support libs". Thank you! – Laiv Apr 27 '16 at 17:15
1

This is a very bad idea. You shouldn't be doing this. If you really want to do this, stop using java -- it's totally inappropriate for the task at hand. You seem to not understand OO -- if you did you wouldn't be asking this question. Java, despite its common misuses, is an OO language and should be treated as such.

The first thing you should try is polymorphism. Have all the classes implement a basic tree/graph interface and a setValue() method that sets the value on the given object and walks the graph to each related object also calling setValue().

The next thing you should try is an event driven approach. Have objects register as event handlers, then raise an event containing the value to be set. Have the handlers set the appropriate values in the appropriate way.

If you use reflection you'll end up with unreadable/unmaintainable code that is very error prone and which will probably stop working as soon as you upgrade java or change a class. It will have a very short shelf-life.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.