Nick
Nick

Reputation: 5198

Why are these hidden static methods sometimes not detected?

Sorry for the vague title; I'm not entirely sure what the problem is.

Background

In short: child classes of a certain base class must define 3 specific static methods, hiding the base class' static methods. An implementation description class checks this on initialization. Seemingly at random when running the application, however, I get run time exceptions during initialization saying that I haven't properly reimplemented the methods. But I am working in unrelated classes elsewhere when this happens, as rarely as it does, and simply shuffling the order of the methods fixes it for another long while.

Code

So, three classes: The Base, the Derived, and the AlgImplementation class:

AlgImplementation constructor:

/* verifying that the extending class has implemented these methods */
        if (this.getAlgorithmClassName() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassName() method from as specified.");
        }
        if (this.getAlgorithmClassDescription() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassDescription() method from as specified.");
        }
        if (this.getAlgorithmClassAnalyticLevel() == null) {
            throw new IllegalArgumentException("The Algorithm Class of this algorithm has not re-implemented the getAlgorithmClassAnalyticLevel() method from as specified.");
        }

That's where the problem happens, one of those checks fails. I get the IllegalArgumentException from one or more of the above. I can simply move the order of the implementation around in the derived class, to force a rebuild of that code, and then it works fine.

Base & Derived classes both have the same simple static methods, but the static fields they return are defined differently:

class Derived extends Base {
public static AnalyticLevel getAlgorithmClassAnalyticLevel()
    {
        return ANALYTIC_LEVEL;
    }

    public static String getAlgorithmClassName()
    {
        return NAME;
    }

    public static String getAlgorithmClassDescription()
    {
        return DESCRIPTION;
    }
 }

The above fields are all non-null static final Strings.

Now, in the Derived class I declare a static final AlgImplementation field: public static final AlgImplementation derivedAlg = new AlgImplementation("xyz", Derived.class, "Our XYZ derived class", "");

Finally, the last thing I think you will need to know is that that this AlgImplementation instance does the this for each static method class:

public String getAlgorithmClassName() {
        String className = "";
        try {
            className = (String)algorithmClass.getDeclaredMethod("getAlgorithmClassName", new Class<?>[0]).invoke(null, new Object[0]);
        } catch (Exception e) {
            throw new UnsupportedOperationException("Required static method getAlgorithmClassName() not implemented on "+this.getClass().getName());
        }
        return className;
    }

Finally

So, my question is: How can the check for the derived methods fail if these methods are in fact declared? Is there an issue with declaring a static AlgImplementation field that refers to the very class it is defined in (causing some weird order of compilation issue, or something like that)?

The error is during initialization of Derived class, specifically at the line initializing the static AlgImplementation field, which is why I think there might be a problem with doing that in the Derived class itself.

Upvotes: 2

Views: 140

Answers (2)

Boann
Boann

Reputation: 50031

I suspect the problem is due to initialization order of the static final fields of the classes. By using reflection during class initialization, you're accessing the class before it has fully initialized. If on a derived class, you have the following:

public static final String NAME;
static {
    NAME = "some name";
}

public static final AlgImplementation derivedAlg =
    new AlgImplementation("xyz", Derived.class, "Our XYZ derived class", "");

then AlgImplementation will check the NAME constant after it has been initialized, and will read the "some name" string. If you reverse the order:

public static final AlgImplementation derivedAlg =
    new AlgImplementation("xyz", Derived.class, "Our XYZ derived class", "");

public static final String NAME;
static {
    NAME = "some name";
}

then AlgImplementation will read the constant before it has been assigned, and will read null instead.

I'm not sure if it's possible for this to happen if the NAME is assigned directly by a compile-time constant like this:

public static final String NAME = "some name";

I would have guessed that would prevent the problem, but maybe not. Your statement that "shuffling the order of the methods fixes it for another long while" supports the idea that the problem is due to initialization order. I'd suggest moving the derivedAlg field after all the other constants to encourage it to be initialized last.

Upvotes: 1

Enerccio
Enerccio

Reputation: 251

Static methods do not participate in class hierarchy. You should always use either staticMethod() or Class.staticMethod() instead.

Upvotes: 0

Related Questions