[1.1.1] Trying to read something from the future

Hello,
I followed the example on Perspectives (Introduction) and Perspectives (History).
So far it’s working nice.
But now I try to save and load the perspectives in/from a file.
I get the following IOException.
What I do is just: On the AWT thread, in a temporary file in /tmp

	@Override
	public void savePerspective(String name, File file) throws IOException {
		perspectives.setPerspective(name, perspective);
		control.write(file);
	}

	@Override
	public void loadPerspective(String name, File file) throws IOException {
		control.read(file);
		control.load(name);
	}

I don’t know if it is the problem, but I’m a little bit lazy and I’m using ObjectOutput/InputStream in the custom layout:


// in my custom MultipleCDockableLayout

	@Override
	public void writeStream(DataOutputStream out) throws IOException {
		ObjectOutputStream obj = new ObjectOutputStream(out);
		obj.writeObject(meta);
		out.flush();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void readStream(DataInputStream in) throws IOException {
		try {
			ObjectInputStream obj = new ObjectInputStream(in);
			meta = (WindowType) obj.readObject();
		} catch (ClassNotFoundException e) {
			throw log.errorReadStream(this, e);
		}
	}

The exception:

Exception in thread “AWT-EventQueue-0” java.security.PrivilegedActionException: java.io.IOException: Trying to read something from the future: 291941.1936982272.256 is greater than the current version 1.1.1a
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:697)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: java.io.IOException: Trying to read something from the future: 291941.1936982272.256 is greater than the current version 1.1.1a
at bibliothek.util.Version.checkCurrent(Version.java:137)
at bibliothek.gui.DockFrontend.readBlop(DockFrontend.java:1910)
at bibliothek.gui.DockFrontend.read(DockFrontend.java:1896)
at bibliothek.gui.DockFrontend.read(DockFrontend.java:1884)
at bibliothek.gui.dock.common.CControl$9.read(CControl.java:880)
at bibliothek.gui.dock.support.util.ApplicationResourceManager.readStream(ApplicationResourceManager.java:144)
at bibliothek.gui.dock.support.util.ApplicationResourceManager.readFile(ApplicationResourceManager.java:204)
at bibliothek.gui.dock.common.CControl.read(CControl.java:2600)
at com.anrisoftware.fdsanalysis.windows.docks.dockingframes.DockingFramesDock.loadPerspective(DockingFramesDock.java:126)
at com.anrisoftware.fdsanalysis.windows.docks.api.Dock$loadPerspective.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at com.anrisoftware.fdsanalysis.windows.docks.dockingframes.DocksStorageTest$_manually_store_and_load_perspective_closure3_closure7.doCall(DocksStorageTest.groovy:43)
at com.anrisoftware.fdsanalysis.windows.docks.dockingframes.DocksStorageTest$_manually_store_and_load_perspective_closure3_closure7.doCall(DocksStorageTest.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.Closure.call(Closure.java:411)
at groovy.lang.Closure.call(Closure.java:405)
at groovy.lang.Closure.run(Closure.java:492)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:727)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:688)
at java.awt.EventQueue$3.run(EventQueue.java:686)
… 9 more

I think it’s a bug:

readBlop() will read Version and check it. But writeBlop() is not writing any Version in the stream.

Anyway, why you don’t use ObjectOutput/InputStream? It’s just as fast for your purposes (it’s a GUI anyway, not some high performance library). It shouldn’t matter if it’s using 30 bytes more or needs 100ms more to load.

I will try and use the XML persistence. I hope that is working.

    /**
     * Writes the contents of <code>blop</code> into <code>out</code>.
     * @param blop the {@link Setting}s to write
     * @param out the stream to write into
     * @throws IOException if there are any problems
     */
    public void writeBlop( SettingsBlop blop, DataOutputStream out ) throws IOException{
    	String currentSetting = blop.getCurrentName();
    	
        if( currentSetting == null )
            out.writeBoolean( false );
        else{
            out.writeBoolean( true );
            out.writeUTF( currentSetting );
        }
        
        String[] names = blop.getNames();
        out.writeInt( names.length );
        for( String name : names ){
            out.writeUTF( name );
            write( blop.getSetting( name ), true, out );
        }
        
        write( blop.getCurrentSetting(), false, out );
    }

    /**
     * Reads the contents of <code>in</code> using all the factories that are currently installed
     * on this {@link DockFrontend}, this method does not change any properties of the frontend.
     * @param in the stream to read from
     * @return the {@link Setting}s that were read
     * @throws IOException if <code>in</code> cannot be read properbly
     */
    public SettingsBlop readBlop( DataInputStream in ) throws IOException{
    	SettingsBlop blop = new SettingsBlop();
    	
    	Version version = Version.read( in );
        version.checkCurrent();
        
        String currentSetting = null;
        
        if( in.readBoolean() )
            currentSetting = in.readUTF();
        
        int count = in.readInt();
        for( int i = 0; i < count; i++ ){
            String key = in.readUTF();
            Setting setting = read( true, in );
            blop.put( key, setting );
        }
        
        blop.setCurrent( currentSetting, read( false, in ) );
        return blop;
    }

I think it is fixed in 1.1.2-SNAPSHOT.
I updated to the latest revision and now it works fine.
But still, I don’t know how that bug can be overlooked. Anybody else is saving in XML format?

I think most if not all people are using xml. I have been toying with the idea to remove byte-stream support, but hesitated because of backwards compatibility.

Sometimes I just do overlook something, or miss a test. As compensation I do fix known bugs immediately; but I expect people to contact me if they find an issue (if I would get money for every copy, I would not work this way… :wink: ).

About the question for the ObjectStream: it’s harder to maintain, renaming a field or class gets you into trouble. Also accidentally saving far too much (e.g. the entire application) is really easy with an ObjectStream.

Thank you for your reply.

I don’t really see the advantage of XML.
Can you manipulate the XML to create new layouts?
I think that would be very error prone and troublesome to do.

Btw, you should get money for your time, too.
It’s a very good project. I wish Oracle would integrate a docking framework in JavaSE and I would like that they took your project for that.

Did you tried to get support work like for example SwingLabs or jgoodies?

In my opinion xml has a advantages: you see what has been written (much easier to debug), and it is really easy to add or remove a field when the format changes.

I do not directly manipulate the xml (nor do I suggest anyone should do that), but at least it is a format a human can understand.

And no I did not ask for any support. Primarily because that would mean I really have to invest time - right now I work on the framework when I want to, without any schedules or deadlines to meet.

For automatic tests it’s no difference if XML or binary.
To test I would create a layout, then save and load and compare the layout again.
Should be easy, because you can compare the internal structure of the perspective.

  1. create perspective after the examples in docking-frames-demo-tutorial
  2. save the perspective to file
  3. load the perspective from file
  4. compare the internal structure of the perspective to the expected.