Home > Software design >  Adding functionality to an existing class (using private fields)
Adding functionality to an existing class (using private fields)

Time:07-13

I want to add a few methods to an already-existing class. The class's source code (read-only) is available to me.

The challenge is that these new methods are dependent on a private field of the already-existing class, so inheritance is not an option.

In my opinion, I have two not so favorable options for achieving my goal. One option is to copy all the source code to a new class and add there my new methods. The other option is to use Reflection. Neither are ideal, the first because it is using a sledgehammer to crack a nut. The second, because it is contrary to the main idea of OOP - capsulation.

The question: Is there any other way to accomplish my goal, or am I stuck with only these options?

CodePudding user response:

Natively in java, no, this is not possible.

You should check out Project Lombok, I believe it has something similar to what you are looking for.

If you don't want to use an external library, reflection is going to be your best alternative. Below are two utility methods that can help get you started:

public static boolean setField(Object target, String fieldName, Object value) {
    try {
        var locatedFields = Stream.of(target.getClass().getDeclaredFields()).filter(f -> f.getName().equals(fieldName)).toList();
        assert locatedFields.size() >= 1;
        var f = locatedFields.get(0);
        f.setAccessible(true);
        f.set(target, value);
        return true;
    } catch(IllegalAccessException | IndexOutOfBoundsException e) {
        return false;
    }
}

public static Object getField(Object target, String fieldName) {
    try {
        var locatedFields = Stream.of(target.getClass().getDeclaredFields()).filter(f -> f.getName().equals(fieldName)).toList();
        assert locatedFields.size() >= 1;
        var f = locatedFields.get(0);
        f.setAccessible(true);
        return f.get(target);
    } catch(IllegalAccessException | IndexOutOfBoundsException e) {
        return null;
    }
}

CodePudding user response:

The class is not flexible enough. This is a defect to its code. So reimplement the class under an other name and describe all this in the javadoc. Then add your functionality, maybe with inheritance.

True this is an ugly situation, living with bad and good class. Maybe you even need to apply the adapter pattern changing a good class instance (your copy) back to a bad class (the original).

You might document a technical debt, substituting the implementation with that private field.

One should mention that in case of a public getter, one may hijack the private field and use a second field. But that you would have seen. And makes for complicated semantics.

  • Related