Quantcast
Channel: Undocumented Matlab
Viewing all articles
Browse latest Browse all 219

Using Java 7 in Matlab R2013a and earlier

$
0
0

Today I would like to introduce guest blogger Roderick, who wishes to remain anonymous. Roderick discusses his experience with setting up Matlab to use the latest stable release of Java, namely JVM 1.7, a.k.a. Java 7.

Background and executive summary

I work in the team where I do a lot of research and prototyping with Matlab. The final production code is however coded by a separate development team in Java 7. When running back-tests on our models I have to either ensure my Matlab prototype exactly matches the Java behavior, or to call the Java production code directly. However, although Java 7 has been available since July 2011, the latest official Matlab version (R2013a at this point) still uses the JVM 1.6 (Java 6), which does not allow calling Java 7 code directly. Today’s article contains my experience in trying to let Matlab use JVM 1.7 code.

I urge readers to consider the following before trying the hacks I’ve found:

  • The hacks described below were found to work for Matlab R2012b and R2013a on Windows 64bit. Simulink or any Matlab toolboxes were not tested, nor any other operating systems (although I’ve found most solutions to work on Linux as well).
  • The set of hacks is not complete; some issues remain in the setup of Matlab to use Java 7.
  • As with all other undocumented Matlab features, they may break in future Matlab versions.
  • A future Matlab version (possibly as close as the upcoming R2013b) might be updated use Java 7 natively – the hacks should only be used on versions that have JVM 1.6.

It is worth considering a number of alternatives before trying to setup Matlab with the JVM 1.7:

  • Compiling the Java project using JDK 1.6 instead of JDK 1.7. If you have the source code for a project and no specific Java 7 features are being used in the code, you could simply recompile it using JDK 1.6 or even 1.5. This would be a more advisable approach than switching Matlab to use Java 7, and enable full backward compatibility on Matlab releases as old as R2007b (for 1.6) or R14 SP2 (for 1.5).
  • Use Java Remote Method Invocation (Java RMI). This enables using Java 6 Java code that calls the Java 7 code. It requires some more work starting off, but has the benefit of not needing to switch Matlab to use Java 7. Due to using a different Java virtual machine, it also prevents duplicate dependencies between Matlab and Java code, when a Java project depends on Java libraries on which Matlab also depends. If Java code relies on a different version than Matlab for such a library, this may give problems with the Java classloader that could result in Matlab being unable to add Jar-file(s) to the java classpath – this issue is solved by separating the Java 7 code to use an independent JVM. The Java RMI approach appears to be a longer-term solution than hacking Matlab to use JVM 1.7.

If after considering the alternatives you have a valid use-case for Matlab to call Java 7 code, follow these steps:

  1. Download the latest Matlab release if you can; earlier releases have more issues with JVM 1.7
  2. Setup Matlab to use JVM 1.7
  3. Create a startup function to detect if JVM 1.7 is used; if so, update the default figure’s CreateFcn to force visibility and then use drawnow
  4. Enable the UseOldFileDialogs feature
  5. Copy and patch listdlg.m to remove the hardcoded figure CreateFcn callback override
  6. Copy and patch gui_mainfcn.m to force visibility of GUI objects by using uistack and by recursively flipping the order of all Children property, or by using the supplied code below

The text below details these steps.

Switching Matlab to use the JVM 1.7

To run Java 7 code from Matlab, Matlab needs to use JVM 1.7. To do this, see this MathWorks page, or follow these steps:

  1. Ensure that you are using Java 6 or earlier – no need to do anything if your Matlab already has Java 7
    >> version -java
    ans =
    Java 1.6.0_17-b04 with Sun Microsystems Inc. Java HotSpot(TM) 64-Bit Server VM mixed mode
  2. Download and install JRE 1.7 or JDK 1.7 from the Oracle website
  3. Create a new System Environment Variable called MATLAB_JAVA with the installation folder as its value. For example: “C:\Program Files\Java\jdk1.7.0_21\jre”
  4. Restart Matlab and verify that it picked up the new Java version:
    >> version('-java')
    ans =
    Java 1.7.0_21-b11 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode

Problems and workarounds with Matlab using JVM 1.7

Certain Matlab functionality was found to give issues when using the JVM 1.7. Most problems are related to visibility and display, although most Matlab code ran as-is without issue.

A) Matlab hangs after “Save As” or “Import Data”

Matlab hangs after clicking the <Import Data> button, or when trying to use the <Save As> functionality. This problem seems to be related to opening a certain type of window after which focus is not returned to Matlab. The user is forced to close Matlab via the Windows Task Manager. This problem was found in R2012b and earlier, however it seems fixed in R2013a. I have not found a solution for this problem; perhaps it is related to this issue. Consider importing data via the command line, and first creating a new m-file then open it in the Matlab Editor. Alternatively, if you really get annoyed by this, you could use findobj functionality to disable the Matlab buttons.

B) Java exceptions from java.awt

Exceptions are occasionally thrown when multiple monitors are used, e.g. when moving figures from one screen to the other, or when docking figures. These exceptions can be a bit annoying, but they do not seem critical.

C) Matlab R2012b hangs using uigetfile

Matlab freezes when using uigetfile. It seems R2013a does not have this problem; for R2012b a solution was found by setting the undocumented UseOldFileDialogs feature:

feature('UseOldFileDialogs', 1)
D) Defective Matlab dialog windows

Certain Matlab dialogs, such as questdlg, listdlg and inputdlg are missing some components. For example:

ButtonName = questdlg('What is your favorite color?', 'Color Question', 'Red', 'Green', 'Blue', 'Green');

Defective dialog window with Java 7

Defective dialog window with Java 7

The problem seems to be related to visibility of the objects, whereby the command buttons or input text objects are part of the figure, but they are just not displayed. The same problem was found for Matlab GUIs that are created by Matlab users and in guide.

Solution: force the figure visibility in its CreateFcn callback, by setting the Visible property to ‘on’ and using drawnow.

set(0, 'DefaultFigureCreateFcn', @DefaultFigureCreationFcnForJVM7);
 
function DefaultFigureCreationFcnForJVM7(aObject, aEventdata)
    % PURPOSE: This function acts as the default figure create function to enforce focus for UI dialog objects % when using JVM 7.
    % IN:       - aObject (1x1 float): the handle to figure object
    %           - aEventdata (1x1 struct): the event data
    myDbStack = dbstack();
    if length(myDbStack) > 1 && any(strcmp(myDbStack(2).file, 'hgloadStructDbl.m'))
        % don't force visibility when GUIs are opened
    else
        set(aObject, 'Visible', 'on');
        drawnow();
    end

The UI dialogs flash a bit more when created, due to the fact that they resize and move around the screen for optimal placement. But at least they look ok now:

Fixed dialog window with Java 7

Fixed dialog window with Java 7

This solution works for all dialogs except listdlg, which is hardcoded to disable the figure’s CreateFcn. For listdlg, follow these steps:

  1. Find listdlg.m
    >> which listdlg
    C:\Program Files\MATLAB\R2013a\toolbox\matlab\uitools\listdlg.m
  2. Copy listdlg.m to a personal folder and comment out the figure’s CreateFcn override in the copied file:
    fig_props = { ...
        'name'                   	figname ...
        'color'                  	get(0,'DefaultUicontrolBackgroundColor') ...
        'resize'                 	'off' ...
        'numbertitle'            	'off' ...
        'menubar'                	'none' ...
        'windowstyle'            	'modal' ...
        'visible'                	'off' ...
        ... % comment out the createfcn to empty such that we don't override the specific createfcn for JVM 1.7!    ... %'createfcn'  	''    ...    'position'               	fp   ...
        'closerequestfcn'        'delete(gcbf)' };
  3. Similarly, copy the private functions getnicedialoglocation.m and setdefaultbutton.m and place their entire contents at the end of your copied listdlg.m.
  4. Ensure that your personal folder is higher on the Matlab path than toolbox\matlab\uitools\
E) Custom GUI visibility problems

If you developed custom Matlab GUIs, you might notice visibility problems when opening the GUIs. For example, assume we have developed the following simple GUI:

Sample custom GUI

Sample custom GUI

If we try to open this GUI we see missing objects again:

Defective custom GUI

Defective custom GUI

This problem seems related to the one with the Matlab dialogs, however it does not seem to be resolved by forcing visibility upon figure creation. After much trial and error, it seems we can fix this by playing around with the order of the figure’s Children:

myFigureHandle = TestGUI;
myChildHandles = get(myFigureHandle, 'Children')
set(myFigureHandle, 'Children', flipud(myChildHandles))

Defective custom GUI take #2

Defective custom GUI take #2

Notice that flipping the order of Children in the main figure did not resolve the visibility of objects in the panels. The procedure needs to be done recursively for all the figure’s containers. One more step gives:

set(myChildHandles(1), 'Children', flipud(get(myChildHandles(1), 'Children')))

Defective custom GUI take #3

Defective custom GUI take #3

Solution: for a single solution that applies to all GUIs, you can do the following:

  1. Locate gui_mainfcn.m
    >> which gui_mainfcn
    C:\Program Files\MATLAB\R2013a\toolbox\matlab\guide\gui_mainfcn.m
  2. Copy gui_mainfcn.m to a personal folder and add a new call to a specific function for handling JVM7 issues for GUIs. The location of this function is important, put it just after the following feval command:
    ...
    feval(gui_State.gui_OpeningFcn, gui_hFigure, [], guidata(gui_hFigure), varargin{:});
    % Patched logic to ensure visibility of all objectsHandleJvm7SupportForGUIs(gui_hFigure, guidata(gui_hFigure));...
  3. Place the following code at the end of your copied gui_mainfcn.m file:
    function HandleJvm7SupportForGUIs(aGUIObject, aGUIHandles)
        % PURPOSE: This function hacks around with the focus of objects on a GUI. It was found that GUIs do not
        % work as intended with the jvm 7 setup, and that objects on panels lose focus/visibility.
        % The approach which at is taken now is by flipping the order of childrens in uipanels.
        % Before the order is swapped, the panel is set to be the visible top-layer panel. 
        % IN:       - aGUIObject (1x1 float): the handle the GUI figure
        %           - aGUIHandles (1x1 struct): the GUI handles
        if ~IsJvm7Used()
            return
        end
        myListOfHandleArrayFields = 'tabPanels';
        try
            set(aGUIObject, 'Visible', 'on');
            drawnow();
     
            if isprop(aGUIObject, 'Children')
                myChildren = get(aGUIObject, 'Children');
                myIsMenuItem = false(length(myChildren), 1);
                for i = 1:length(myChildren)
                    if isprop(myChildren(i), 'Type') && strcmp(get(myChildren(i), 'Type'), 'uimenu')
                        myIsMenuItem(i) = true();
                    end
                end
                myChildren(~myIsMenuItem) = flipud(myChildren(~myIsMenuItem));
                set(aGUIObject, 'Children', myChildren);
                drawnow();
            end
     
            myFields = fieldnames(aGUIHandles);
            myIsValid = true(size(myFields));
            for i = 1:length(myListOfHandleArrayFields)
                myIsValid = myIsValid & cellfun('isempty', strfind(myFields, myListOfHandleArrayFields{i}));
            end
            myFields = myFields(myIsValid);
            myPanelFields = {};
            for i = 1:length(myFields)
                if isprop(aGUIHandles.(myFields{i}), 'Type') && strcmp(get(aGUIHandles.(myFields{i}), 'Type'), 'uipanel')
                    myPanelFields =  [myPanelFields; myFields(i)]; %#ok
                end
            end
            for i = 1:length(myPanelFields)
                % allow three layers of panels maximum!
                if isprop(aGUIHandles.(myPanelFields{i}), 'Parent')
                    myParent = get(aGUIHandles.(myPanelFields{i}), 'Parent');
                    if strcmp(get(myParent, 'Type'), 'uipanel')
                        if isprop(myParent, 'Parent')
                            mySecondParent = get(myParent, 'Parent');
                            if strcmp(get(mySecondParent, 'Type'), 'uipanel')
                                uistack(mySecondParent, 'top');
                                drawnow();
                            end
                        end
                        uistack(myParent, 'top');
                        drawnow();
                    end
                end
                uistack(aGUIHandles.(myPanelFields{i}), 'top'); 
                drawnow();
                set(aGUIHandles.(myPanelFields{i}), 'Children', flipud(get(aGUIHandles.(myPanelFields{i}), 'Children'))); 
                drawnow();
            end
        catch myException
            disp(['WARN: could not initialize the GUI correctly with JVM 1.7 override logic, in ', mfilename()]);
            myException.getReport()
        end
     
    function theIsJvm7Used = IsJvm7Used()
        % PURPOSE: To indicate if Matlab is setup to use jvm 7
        % OUT:      - theIsJvm7Used (1x1 logical): whether or not JVM 7 is used
        myJavaVersion = version('-java');
        theIsJvm7Used = strcmpi(myJavaVersion(1:8), 'java 1.7');
  4. Ensure that your personal folder is higher on the Matlab path than toolbox\matlab\uitools\

Fixed custom GUI

Fixed custom GUI

Notice that the panel names are still missing. So far no solution for this has been found. Perhaps this can be overcome using the fact that uipanel titles are simply hidden children of the panel object.

 
Related posts:
  1. Matlab-Java interface using a static control The switchyard function design pattern can be very useful when setting Matlab callbacks to Java GUI controls. This article explains why and how....
  2. FindJObj – find a Matlab component’s underlying Java object The FindJObj utility can be used to access and display the internal components of Matlab controls and containers. This article explains its uses and inner mechanism....
  3. JMI – Java-to-Matlab Interface JMI enables calling Matlab functions from within Java. This article explains JMI's core functionality....
  4. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
 

Viewing all articles
Browse latest Browse all 219

Trending Articles