Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Classname in static methods of abstract classes

Tags:

matlab

I would like to access the class name of the concrete class that's invoking a static method implemented in an abstract superclass.

This is the code (part of) of the abstract superclasss:

classdef (Abstract) AbstractJobProcessor < handle

    properties (Abstract, Constant)
        VERSION_MAJOR;
        VERSION_MINOR;
        LAST_MODIFIED;
    end 

    ...


methods (Static)
    function res = getVersionMajor;
        res = AbstractJobProcessor.VERSION_MAJOR;
    end 

    function res = getVersionMinor
        res = AbstractJobProcessor.VERSION_MINOR;
    end

    function res = getVersionInfo
        res = sprintf('**CLASSNAME**: v%d.%02d (last modified: %s)',... 
            AbstractJobProcessor.VERSION_MAJOR,...
            AbstractJobProcessor.VERSION_MINOR,...
            AbstractJobProcessor.LAST_MODIFIED);
    end

end
...

Basically, I would like to access the classname of the concrete subclass and use it in the method getVersionInfo in place of the string **CLASSNAME**.

All the methods returning meta information about a class (that I have found in the documentation) require a reference to an instance of the class (like, for example, mc = metaclass(object)).

like image 825
Antonio Sesto Avatar asked Aug 31 '25 02:08

Antonio Sesto


1 Answers

The below function will give you what you want - subclass name, that was used when invoking an (inherited) static superclass method. Just call it inside your superclass method like you would any normal function:

className = getStaticCallingClassName();

What it does handle:

  • Both the case when method was invoked programmatically (i.e. by a running script / function), as well as when it was invoked from the command window.
  • Arbitrarily nested package names (i.e. classes located inside directories prefixed with +).

What it does not handle:

  • Does not work if the static method is called in a non-static context, i.e. on an object instance. But you should not be using such syntax anyway. This would've been possible if we were able to use evalin with 'caller' workspace recursively, but it does not work this way.

A brief explanation behind the idea: second entry in the stack trace, produced by dbstack, would correspond to the superclass, which we can use to extract the static method name. The next steps depend on:

  1. If the method is invoked programmatically, third stack entry would point us to a line in the the parent script/function which we need to read, e.g. using dbtype. All that's left to do is extract the subclass name using regexp based on the method name.
  2. If the method is invoked from command window, we query the last command and use that as the input for our regular expression.

Note that even if stack has 3 entries or more, it doesn't mean that the method was invoked programmatically. For example, if we've stopped on a breakpoint somewhere and invoke the method from command window, stack trace would be long, but regexp based on the line from the third stack trace entry will not give us the answer. In this case we fall back to the command window approach.

Warning: it heavily relies on undocumented features and may break in any feature release. Tested on Matlab 2015b, but should work on most previous releases as well. Some may say it is quite dirty, but it works very well, and it's the only method that I'm aware of to achieve such a behavior.

function [className, fullPath] = getStaticCallingClassName()
    ST = dbstack('-completenames');
    % First one is getStaticCallingClassName, second one is the superclass
    methodName = char(regexp(ST(2).name, '[^\.]([^.]*)$', 'match'));
    % matches string (combination of alphanumeric/underscore/dot characters) preceeding the given method call.
    pattern = sprintf('[\\w.-]*(?=.%s)', methodName);

    % If the parent called static method programmatically, we should be able to find it via the next (third) stack trace
    if length(ST) > 2
        command = evalc('dbtype(ST(3).file, num2str(ST(3).line))');
        className = char(regexp(command, pattern, 'match'));
    else % was likely called from command window. Long stack trace means that we're simply waiting in a breakpoint somewhere
        className = []; % go straight to command window approach
    end

    if isempty(className) % means that static method was called directly from command window
        javaHistory = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory();
        command = char(javaHistory(end));
        className = char(regexp(command, pattern, 'match'));
    end

    fullPath = which(className);
end
like image 75
nirvana-msu Avatar answered Sep 03 '25 05:09

nirvana-msu