Once again I welcome Donn Shull, who concludes his series on Matlab’s undocumented UDD mechanism with a discussion of the UDD-Java relationship.
Introduction to the UDD-Java relationship
Over the course of this series we have mentioned connections between UDD and Java. In UDD Events and Listeners [1] we described how in Matlab each Java object can have a UDD companion. In Hierarchical Systems with UDD [2] we briefly noted that a UDD hierarchy may be passed to Java. This suggests that there is a two way relationship between between UDD and Java.
In this article we will use some undocumented built-in methods such as java and classhandle to explore the UDD-Java relationship. We have used built-in methods for UDD objects before. We have also mentioned the importance of studying code from The MathWorks. When you come across something that looks like it may be a UDD method you can check with the which command:
>> which java -all
C:\MATLAB\R2010b\toolbox\matlab\general\java.m
java is a built-in method % javahandle.com.mathworks.hg.peer.Echo method
java is a built-in method % ui.figure method
java is a built-in method % hg2utils.HGHandle method
java is a built-in method % JavaVisible method
java is a built-in method % hg.figure method
java is a built-in method % hg.GObject method
java is a built-in method % schema.class method
java is a built-in method % handle.handle method
java is a built-in method % schema.method method
C:\MATLAB\R2010b\toolbox\rptgen\rptgen\@sgmltag\java.m % sgmltag method
If you find schema.class
in the comments for built-in methods, then the method is a general UDD method.
UDD javahandle companions for Java object
Whenever a Java class is instantiated in Matlab, it is possible to create a companion UDD object [3]. The created companion can be in either the javahandle
or the javahandle_withcallbacks
package. The primary reason for creating the companion object is to avoid memory leaks [4] when attaching a Matlab callback to a callback property. It makes sense in general to use the javahandle_withcallbacks
package.
>> % creage a java instance and the companion UDD object
>> javaFrame = javax.swing.JFrame;
>> % dot notation
>> javaFrameUDD = javaFrame.handle('CallbackProperties');
>> % or Matlab notation
>> javaFrameUDD = handle(javaFrame,'CallbackProperties');
We can use the built-in classhandle method to inspect our UDD companion object. This can be used, for example, to obtain a list of the events that the Java class generates:
>> % use classhandle to list a java classes events
>> jch = javaFrame.handle.classhandle;
>> for index = 1:numel(jch.Events), disp(jch.Events(index).Name); end
MouseWheelMoved
MouseClicked
MouseEntered
MouseExited
MousePressed
MouseReleased
WindowGainedFocus
WindowLostFocus
WindowActivated
WindowClosed
WindowClosing
WindowDeactivated
WindowDeiconified
WindowIconified
WindowOpened
ComponentHidden
ComponentMoved
ComponentResized
ComponentShown
MouseDragged
MouseMoved
ComponentAdded
ComponentRemoved
AncestorMoved
AncestorResized
FocusGained
FocusLost
WindowStateChanged
HierarchyChanged
CaretPositionChanged
InputMethodTextChanged
PropertyChange
KeyPressed
KeyReleased
KeyTyped
>> % Use one of the object's callbacks
>> set(javaFrameUDD,'WindowGainedFocusCallback',@myCallbackFcn);
If we do not wish to use callback properties, then we can create our UDD companion in the javahandle
package and use handle.listener to respond to events.
javaFrame = javax.swing.JFrame;
javaFrameUDD = javaFrame.handle;
lis = handle.listener(javaFrameUDD,'WindowGainedFocus',@myCallbackFcn);
Passing UDD objects to Java code
You can pass any UDD object to your Java classes in Matlab. Matlab will create a Java bean adapter for the UDD object. The bean adapter created is a subclass of com.MathWorks.jmi.bean.UDDObject
. UDDObject
implements the Java interfaces com.MathWorks.jmi.bean.DynamicProperties
, com.MathWorks.jmi.bean.MTObject
, com.MathWorks.jmi.bean.TreeObject
, and com.mathworks.services.Browseable
.
The generated bean adapter will have the methods of the parent class the methods of the UDD class, as well as set and get methods for the class properties. To understand how this works, let’s start with our simple.object
and use the java method to inspect the bean adapter:
>> myObj = simple.object('myObj', 2);
>> % using dot notation with the java method
>> myObj.java.getClass
ans =
class objectBeanAdapter0
>> myObj.java.methods
Methods for class objectBeanAdapter0:
acquireReference createNullMatlabObjectListener lastDown
addBelow createNullPropertyChangeListener left
addBrowseableListener dialog notify
addFirstBelow disp notifyAll
addLeft dispose objectBeanAdapter0
addMatlabObjectListener equals releaseReference
addObjectPropertyChangeListener findProperty removeBrowseableListener
addRight firstDown removeMatlabObjectListener
browseableCanHaveChildren getChildAt removeObjectPropertyChangeListener
browseableChild getChildCount right
browseableChildCount getClass setDirtyFlag
browseableChildFetchCount getClassName setDynamicPropertyValue
browseableChildren getDynamicProperties setName
browseableDataObject getDynamicPropertyValue setPropertyValue
browseableDisplayObject getIndex setThreadSafetyCheckLevel
browseableHasChildren getIndexOfChild setValue
browseableNChildren getName toString
browseableNextNSiblings getNewInstance up
browseableNextSibling getPropertyValue updateCache
browseableParent getValue updateChildCount
browseablePrevNSiblings hashCode updateIndex
browseablePrevSibling isDirty wait
checkThreadSafety isLeaf
clearDirtyFlag isObservable
compareTo isValid
The parent class has added a large number of methods to the bean adapter for our original class. By looking at the list we can see our dialog and disp methods. There are also getName, setName, getValue, and setValue methods for our classes properties. The rest of the methods were inherited from the base UDDObject
superclass. We can use any superclass method directly with the bean adapter object. For example:
>> myObj.java.getPropertyValue('Name')
ans =
myObj
Java interface class
To be able to use our UDD object in user-written Java code, we need a Java interface class for it. While we could manually write an interface file, UDD provides a very handy convenience method to automatically create the interface file. For this, we use the classhandle method again. The schema.class
object obtained using classhandle has a method called createJavaInterface that takes two string arguments: the Java interface classname, and the folder in which to place the interface file. The steps to create and use this interface file are:
- Create and test your UDD class
- Create a Java interface file using
schema.class
‘s CreateJavaInterface - Modify your UDD class definition file (schema.m) to reference the Java interface file
- Create the Java code that uses your class
For example, to create a Java interface file for the simple object we created above, use the following commands in Matlab:
classH = classhandle(myObj);
classH.createJavaInterface('simpleObjectInterface',pwd);
This will create the following simpleObjectInterface.java file in the current working directory:
public interface simpleObjectInterface
extends com.mathworks.jmi.bean.TreeObject
{
/* Properties */
public java.lang.String getName();
public void setName(java.lang.String value);
public double getValue();
public void setValue(double value);
/* Methods */
public void dialog();
public void disp();
}
The interface file contains set and get accessor methods for our UDD object properties, and Java prototypes for the UDD methods (in our case, dialog and disp).
The next step is to modify our class definition file (schema.m) to reference the Java interface file we have created. This modification provides the information that Matlab needs to create the bean adapter that implements the Java interface:
simpleClass = schema.class(simplePackage, 'object');
simpleClass.JavaInterfaces = { 'simpleObjectInterface' };
We can verify that the generated bean adapter implements the interface using Java Reflection techniques. As always when we have made changes to the class definition file, we need to use the clear classes command, and then recreate our objects:
>> myObj = simple.object('myObj', pi)
myObj =
Name: myObj
Value: 3.141593
>> myObjBean = java(myObj)
myObjBean =
Name: myObj
Value: 3.141593
>> interfaces = myObjBean.getClass.getInterfaces
interfaces =
java.lang.Class[]:
[java.lang.Class]
>> interfaces(1)
ans =
interface simpleObjectInterface
Using UDD in Java
Let’s create a simple Java class that illustrates passing a UDD object to Java. Here we will just have two methods: The first gets the Value property from a class instance and doubles it; the second launches the class instance dialog:
public class accessUDDClass
{
double localValue;
public void accessUDDClass() {
}
public void doubleValue(simpleObjectInterface UDDObj) {
localValue = UDDObj.getValue();
UDDObj.setValue(2*localValue);
}
public void launchDialog(simpleObjectInterface UDDObj) {
UDDObj.dialog();
}
}
If we have set up the Java compiler and environment variables correctly, we can compile our interface and Java class files from inside Matlab using the system command (alternately, we can compile using any external Java compiler or IDE):
>> system('javac accessUDDClass.java simpleObjectInterface.java')
ans =
0
Now test our simple Java class with the UDD object created earlier:
>> javaObj = accessUDDClass
javaObj =
accessUDDClass@eb9b73
>> javaObj.doubleValue(myObj) % pi => 2*pi
>> myObj
myObj =
Name: myObj
Value: 6.283185
This concludes the UDD series. I would like to thank Yair for his help in preparing and presenting this information.
Editor’s note
I would like to thank Donn for his enourmously detailed work on UDD, and for preparing it in easy-to-follow articles. I can personally attest to the huge time investment it has taken him. I trully believe he deserves a warm “thank you” from the Matlab community. Please visit Donn’s website [5], or add a short comment [6] below.
In the following weeks, I return to the regular stuff that made this website famous: solving day-to-day Matlab problems using simple undocumented built-in Matlab gems.
– Yair
4 Comments To "UDD and Java"
#1 Comment By Matt Whitaker On March 24, 2011 @ 11:51
I totally agree Yair. I have been reading this series closely and have learned an immense amount of detail on these UDD objects.
Bravo, Donn! Much appreciated
#2 Comment By julien On April 6, 2011 @ 00:18
Thanks Donn for these excellent and well written articles !
I have a question, maybe you could help me. My problem is simple, I would like to trigger a Matlab callback when the value of a property of a java object changes.
I tried 2 things : First is to set ‘PropertyChangeCallback’ to the UDD companion of my java Object.
When I modify the “Text” property, it works perfectly well.
However, the callback does not trigger on every properties. For example,
So, my second try was to use UDD property event mechanism.
This works, but only when the property value is changed from the set method on the UDD object :
What I would like is to be able to trigger the callback on all properties of java objects and from property changes which come from java side (j.setProperty syntax) or Matlab side (set(obj,’Property’,Value) syntax).
Do you know how I could do that from Matlab side ?
Thank you very much in advance for your help.
#3 Comment By Donn On April 6, 2011 @ 10:49
@julien – I do not have an answer for you. Perhaps a person with more knowledge of java can explain why ‘PropertyChange’ is only fired for a subset of JLabels properties. As for the ‘PropertyPostSet’ listener this looks like a bug to me. I suspect that the MATLAB notation changes the UDD peer and generates the ‘PropertyPostSet’ event and synchronizes the java objects property. When the java notation is used it may be that the java object is set and then the UDD object is synchronized. If that is the order of events then this may be related to MATLABs lack of support for asynchronous events in COM objects. Both the java peer mechanism and COM support are based on UDD. The MathWorks explicitly states with COM that asynchronous events are not supported.
Sorry I can’t be of more help,
Donn
#4 Comment By julien On April 6, 2011 @ 12:24
Thank you for your answer Donn ! Unfortunately, I will have to deal with Bound properties (JavaBeans) to be sure that the properties I want to monitore fire PropertyChange events…
Thanks again for your articles,
Best Regards