Preventing serialisation - matlab

I have a Matlab class where implementing serialisation and deserialisation would be painful, and not needed.
Therefore, I have overloaded saveobj as follows:
function sobj = saveobj(self)
sojb = [];
error(['atmlab:' mfilename ':nostoring'], ...
['You tried to store %s %s. Loading is impossible, ' ...
'therefore I refuse to store. Sorry.'], ...
class(self), self.name);
end
Unfortunately, when I test this, Matlab tries to be helpful and turns the warning into an error (twice for some reason):
>> save('/tmp/test.mat', 'X')
Warning: While saving an object of class 'SatDataset':
You tried to store SatDataset amsua. Loading is impossible, therefore I refuse to store. Sorry.
(Type "warning off atmlab:SatDataset:nostoring" to suppress this warning.)
Warning: While saving an object of class 'SatDataset':
You tried to store SatDataset amsua. Loading is impossible, therefore I refuse to store. Sorry.
(Type "warning off atmlab:SatDataset:nostoring" to suppress this warning.)
I can turn the warning into an error using an undocumented feature:
>> warning error atmlab:SatDataset:nostoring
>> save('/tmp/test.mat', 'X')
Error using save
While saving an object of class 'SatDataset':
You tried to store SatDataset amsua. Loading is impossible, therefore I refuse to store. Sorry.
Unexpected error status flag encountered. Resetting to proper state.
But this is not satisfactory, as I don't want to rely on undocumented features and I certainly don't want to force users to do so.
How can I effectively throw an error, prevent users from trying to serialise objects from my class?
By request, a minimum example to reproduce the situation:
% in TestClass.m
classdef TestClass < handle
methods
function sobj = saveobj(self)
sojb = [];
error('Unable to store %s objects', class(self));
end
end
end
% on the interactive prompt:
>> t = TestClass();
>> save('/tmp/fubar.mat', 't');
Warning: While saving an object of class 'TestClass':
Unable to store TestClass objects
Warning: While saving an object of class 'TestClass':
Unable to store TestClass objects

Personally, I prefer to mark all properties as Transient, and let the object effectively have an invalid state that is the result of saving/loading. It's remarkably hard to prevent MATLAB from saving your data, and your workaround might significantly interfere with your users' workflow.

Your code actually throws the error, you should replace your call of error() by warning()

Related

Can't use Ignite loadCache method with IgniteBiPredicate

I'm using Apache Ignite as a cache backed by a postgres database too large to initialize all at once. Instead, I want to load selective pieces into my cache on an as-needed basis. I wanted to do this via loadCache (since readThroughEnabled mode only works for simple cache operations, which I can't guarantee we'll be using), which accepts an IgniteBiPredicate as an argument. However, whenever I try to use an IgniteBiPredicate as filter, I get ClassCastExceptions that prevent me from loading the cache.
This is for a single node of Ignite local to my server. I have tried taking my cache and calling "loadCache(biPredicate, null)" on it to attempt to load the specific data I want. This is an example of my code with some domain specifics stripped out:
public void initFoo(int key){
IgniteCache<Integer, Foo> myCache = getCache(Foo.class);
if (myCache != null){
myCache.loadCache(new IgniteBiPredicate<Integer, Foo>() {
#Override
public boolean apply(Integer integer, Foo foo){
return integer == key;
}
}, null);
}
}
I would expect this to result in my cache being loaded, at least the part that I care about for this particular entry. Instead I see
"Failed to load cache: Foo"
...(lots of nested exceptions eventually leading to)
...
"Caused by: jvaa.lang.ClassCastException:
org.apache.ignite.internal.binary.BinaryObjectImpl cannot be cast to
com.sms.Foo"
I am confident this is not a problem in my cache configuration (at least at the level of the Java object) as when I did a simple loadCache with no arguments, the entire cache loaded fine and was usable. Am I doing something wrong?
Basically you are getting BinaryObject's instead of your POJO objects.
You can just choose to work with BinaryObject's, or there should be a setting to reverse this behavior. Try cacheCfg.setStoreKeepBinary(false) when creating cache, for example.
UPD: I have checked it and it seems that storeKeepBinary isn't used. Anyway, you can do Foo foo = binaryObject.deserialize(); if you like. I'm still not sure if this is configurable or if this closure just gets what is thrown to it.

Why does my listener get deleted when I saveobj()?

Suppose I have two classes, a < matlab.mixin.Copyable and b < handle.
Here's a:
classdef a < matlab.mixin.Copyable
properties
hListener
end
methods
function obj = a(b)
obj.newListener(b);
end
function newListener(obj, b)
obj.hListener = addlistener(b, 'bEvent', #(o,e) disp('Received bEvent'));
end
function sobj = saveobj(obj)
sobj = copy(obj);
delete(sobj.hListener);
sobj.hListener = [];
end
end
end
and b:
classdef b < handle
events
bEvent
end
methods
function obj = b
end
function raiseEvent(obj)
notify(obj, 'bEvent');
end
end
end
I use saveobj in a to delete the listener upon save. I will manually re-instantiate a listener when I load the classes later.
a inherits from matlab.mixin.Copyable so I can do a copy during the saveobj operation - this way I can make a copy of the original object and change it, without affecting the original, and then save that to a MAT-file. (Supposedly - this is where my question is going.)
Now I run the following at the command line:
>> bob = b; alice = a(bob);
>> bob.raiseEvent
Received bEvent
Everything works. Now, let's save:
>> save ab alice bob
and try to raise the event again:
>> bob.raiseEvent
% NOTHING HAPPENS!
Turns out the listener is gone!
>> alice.hListener
handle to deleted listener
What is going on here? Why is the listener object shared between sobj and obj in the saveobj method?
In researching this question I discovered the answer. I figured I'd add to the body of knowledge around these parts.
Per the documentation for matlab.mixin.Copyable,
Given a call to the matlab.mixin.Copyable copy method of the form:
B = copy(A);
Under the following conditions, produces the described results:
A has dynamic properties — copy does not copy dynamic properties. You can implement dynamic-property copying in the subclass if needed.
A has no non-Dependent properties — copy creates a new object with no property values without calling the class constructor to avoid introducing side effects.
A contains deleted handles — copy creates deleted handles of the same class in the output array.
A has attached listeners — copy does not copy listeners. (emphasis added)
A contains objects of enumeration classes — Enumeration classes cannot subclass matlab.mixin.Copyable.
A delete method calls copy — copy creates a legitimate copy, obeying all the behaviors that apply in any other usage.
What I took this to mean originally was that a copy call would skip over a property whose value is a listener handle. Apparently what it means is that rather than skipping the property altogether, copy makes a reference to the original listener object, i.e., it copies the handle to the listener but not the listener itself.
Of course, when you load the copied object and it has that reference to listener, it'll complain:
Warning: Cannot load an object of class 'listener':
No matching constructor signature found.
Warning: During load:
An invalid default object has been detected while loading a heterogeneous array of
class event.listener. An empty array of class event.listener will be returned.
The easiest thing to do, then, is to modify saveobj:
function sobj = saveobj(obj)
sobj = copy(obj);
sobj.hListener = [];
end
Here, I don't explicitly call delete on the listener, as this would delete the actual object. Instead, I just clear the reference to that object.

Matlab oop - Clearing object from memory does not call 'delete' method as expected

Context
I created two similar PrimarySettings and SecondarySettings handle classes in matlab to store settings of my own and was willing to group both of them in a bigger AllSettings class for convenience.
All classes have a PropertyChanged event to monitor for settings modifications.
The code for all classes can be visualized from here.
Problem
When I test PrimarySettings and SecondarySettings classes to check if their are effectively calling their delete method when all instances are no longer referenced in the code I have no issue:
>> ps = PrimarySettings();
>> clear ps;
Destroying PrimarySettings.
>> ss = secondarySettings();
>> clear ss;
Destroying SecondarySettings.
The same when I test for proper event notifications:
>> as = AllSettings();
>> as.PrimarySettings.Titi = 12;
Property 'PrimarySettings.Titi' modified.
The problem is only with the AllSettings class for which delete method is never called at all:
>> as = AllSettings();
>> clear as;
!!!!!! here delete method is not called !!!!!
The object is still in memory while it is no longer referenced. This can be tested like this:
>> clear classes
Warning: Objects of 'SecondarySettings' class exist. Cannot clear this class or any of its superclasses.
Warning: Objects of 'PrimarySettings' class exist. Cannot clear this class or any of its superclasses.
Warning: Objects of 'AllSettings' class exist. Cannot clear this class or any of its superclasses.
Investigations
The problem seems linked to the way I am attaching the PropertyChanged event (the listener is probably still alive).
Unfortunately I truly don't understand why. Indeed, the code for attaching to events is very similar in all the classes I created.
PrimarySettings and SecondarySettings:
for idx = 1:propCount;
listener = addlistener(obj, meta.PropertyList(idx).Name, 'PostSet', #obj.onPropertyChanged);
listener.Recursive = true;
end
AllSettings:
for idx = 1:propCount;
propName = meta.PropertyList(idx).Name;
listener = addlistener(obj, propName, 'PostSet', #obj.onPropertyChanged);
listener.Recursive = true;
listener = addlistener(obj.(propName), 'PropertyChanged', #obj.onSubPropertyChanged);
listener.Recursive = true;
end
NB: If I comment the second listener (i.e. onSubPropertyChanged) then the AllSettings class works as expected!
Question
What's wrong with the deletion of AllSettings objects ?
If you need a specific diagnosis of the issue, I'm afraid you'll need to post more code, so we can trace through what's going on exactly.
But I would expect that the issue is that one of your listeners is storing a reference to another of your objects in a way that you're not expecting, so it's not getting destroyed when you call clear.
To help you diagnose things further, note that there are two ways to create listeners:
Using addlistener, which ties the listener's lifecycle to the object that is the source of the event.
Constructing the listener directly using event.listener, where the listener exists only while it is in scope, and is not tied to the event-generating object's existence.
For more information, see the section "Ways to create listeners" in this documentation page on Events and Listeners — Syntax and Techniques.
Hope that helps!

Error while entering data in a class properties in matlab

I have made following class in matlab.
classdef details
% SCORES Summary of this class goes here
% Class for stroring the individual scores array of each of the
% comparison of the models and the test files including the number of
% coefficients used and number of gaussian
properties(SetAccess=public)
name;
rollno=0;
batch=0;
branch;
image;
end
methods
end
end
and i am accessing it in following way
detail=details;
detail.name=get(handles.edit2,'string');
detail.rollno=str2num(get(handles.edit3,'string'));
On running the program its giving following error:
??? No public field rollno exists for class details.
I don't know where is the error??????
I'm having the same problem as you, and I think I've found the cause. If you have a variable in the MATLAB workspace that is defined by the class, you cannot change it. That is, you probably have a test variable that is a "details" class, and was initialized before you added the "rollno" propriety. Try deleting any test variables.
Try changing this
properties(public)
to this
properties(SetAccess = public)
See the Matlab documentation for more info

ScalaTest: Issues with Singleton Object re-initialization

I am testing a parser I have written in Scala using ScalaTest. The parser handles one file at a time and it has a singleton object like following:
class Parser{...}
object Resolver {...}
The test case I have written is somewhat like this
describe("Syntax:") {
val dir = new File("tests\\syntax");
val files = dir.listFiles.filter(
f => """.*\.chalice$""".r.findFirstIn(f.getName).isDefined);
for(inputFile <- files) {
val parser = new Parser();
val c = Resolver.getClass.getConstructor();
c.setAccessible(true);
c.newInstance();
val iserror = errortest(inputFile)
val result = invokeparser(parser,inputFile.getAbsolutePath) //local method
it(inputFile.getName + (if (iserror)" ERR" else " NOERR") ){
if (!iserror) result should be (ResolverSuccess())
else if(result.isInstanceOf[ResolverError]) assert(true)
}
}
}
Now at each iteration the side effects of previous iterations inside the singleton object Resolver are not cleaned up.
Is there any way to specify to scalatest module to re-initialize the singleton objects?
Update: Using Daniel's suggestion, I have updated the code, also added more details.
Update: Apparently it is the Parser which is doing something fishy. At subsequent calls it doesn't discard the previous AST. strange. since this is off topic, I would dig more and probably use a separate thread for the discussion, thanks all for answering
Final Update: The issue was with a singleton object other than Resolver, it was in some other file so I had somehow missed it. I was able to solve this using Daniel Spiewak's reply. It is dirty way to do things but its also the only thing, given my circumstances and also given the fact I am writing a test code, which is not going into production use.
According to the language spec, no, there is no way to recreate singleton objects. However, it is possible to reflectively invoke the constructor of a singleton, which overwrites the internal MODULE$ field which contains the actual singleton value:
object Test
Test.hashCode // => e.g. 779942019
val c = Test.getClass.getConstructor()
c.setAccessible(true)
c.newInstance()
Test.hashCode // => e.g. 1806030550
Now that I've shared the evil secret with you, let me caution you never, ever to do this. I would try very very hard to adjust the code, rather than playing sneaky tricks like this one. However, if things are as you say, and you really do have no other option, this is at least something.
ScalaTest has several ways to let you reinitialize things between tests. However, this particular question is tough to answer without knowing more. The main question would be, what does it take to reinitialize the singleton object? If the singleton object can't be reinitialized without instantiating a new singleton object, then you'd need to make sure each test loaded the singleton object anew, which would require using custom class loaders. I find it hard to believe someone would design something that way, though. Can you update your question with more details like that? I'll take a look again later and see if the extra details makes the answer more obvious.
ScalaTest has a runpath that loads classes anew for each run, but not a testpath. So you'll have to roll your own. The real problem here is that someone has designed this in a way that it is not easily tested. I would look at loading Resolver and Parser with a URLClassLoader inside each test. That way you'd get a new Resolver each test.
You'll need to take Parser & Resolver off of the classpath and off of the runpath. Put them into a directory of their own. Then create a URLClassLoader for each test that points to that directory. Then call findClass("Parser") on that class loader to get it. I'm assuming Parser refers to Resolver, and in that case the JVM will go back to the class loader that loaded Parser to get Resolver, which is your URLClassLoader. Do a newInstance on the Parser to get the instance. That should solve your problem, because you'll get a new Resolver singleton object for each test.
No answer, but I do have a simple example of where you might want to reset the singleton object in order to test the singleton construction in multiple, potential situations. Consider something stupid like the following code. You may want to write tests that validates that an exception is thrown when the environment isn't setup correctly and also write a test validates that an exception does not occur when the environment is not setup correctly. I know, I know everyone says, "Provide a default when the environment isn't setup correctly." but I DO NOT want to do this; it would cause issues because there would be no notification that you're using the wrong system.
object RequiredProperties extends Enumeration {
type RequiredProperties = String
private def getRequiredEnvProp(propName: String) = {
sys.env.get(propName) match {
case None => throw new RuntimeException(s"$propName is required but not found in the environment.")
case Some(x) => x
}
}
val ENVIRONMENT: String = getRequiredEnvProp("ENVIRONMENT")
}
Usage:
Init(RequiredProperties.ENVIRONMENT)
If I provided a default then the user would never know that it wasn't set and defaulted to the dev environment. Or something along these lines.