United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6278300 : sun.print.Win32MediaSize deserialization error

Details
Type:
Bug
Submit Date:
2005-05-31
Status:
Open
Updated Date:
2012-01-16
Project Name:
JDK
Resolved Date:
Component:
client-libs
OS:
windows_xp
Sub-Component:
2d
CPU:
x86
Priority:
P5
Resolution:
Unresolved
Affected Versions:
5.0
Targeted Versions:

Related Reports

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

(Does not appear to be specific to particular Windows version.)

A DESCRIPTION OF THE PROBLEM :
Deserialization of a javax.print.attribute.standard.MediaPrintableArea printer attribute fails when the serialization happened in a prior invocation of the program. Unclear what the nature of the initialization problem is, but it works during the same invocation of the program as the serialization. Exception message suggests a problem with the implementation of the javax.print.attribute.EnumSyntax.readResolve method call in sun.print.Win32MediaSize.

The stack trace suggests that the valid range test in readResolve is not functioning properly because of the fact that the range is in descending rather than ascending order--but that's just our guess. That is, it says zero is not a valid value because it doesn't fall in the range 0 to -1:

java.io.InvalidObjectException: Integer value = 0 not in valid range 0..-1for cl
ass class sun.print.Win32MediaSize
        at javax.print.attribute.EnumSyntax.readResolve(Unknown Source)
(see Error Messages for full stack trace)

My code is attempting to deserialize a javax.print.attribute.standard.MediaPrintableArea object. Depending upon the specific attributes, this either succeeds or fails (in our case, with the stack trace shown; there may be other similar problems we haven't encountered yet). The problem appears when there is a non-standard page size involved (in our test case with a Canon S750 driver and the 4 x 6 size [a size supplied with the Canon driver because of its potential use to print on expensive Canon photo paper]).

Note that this only seems to happen when the deserialization occurs as the program is initializing. In the course of a single program invocation, the deserialization operates correctly. If the serialization sits in Preferences when the program starts, it fails (odd--and frustrating since that's sort of the whole point of saving the media size).



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
You'll need a Windoze box (we tested on both XP and 2K w/ sp4 so either should be an okay testbed).

Get the Canon driver for the S750 from this URL:

http://consumer.usa.canon.com/ir/controller?act=SupportSearchResultsAct&keyword=S750&Submit.x=39&Submit.y=11

Click on Drivers and get the one for Win2K or XP.

Install it (you won't actually need a printer to see the problem).

Run the test program. When the printer dialog comes up, go to the  Page Setup tab; choose the 4 x 6 Media and change the margins. Press the Print button (this serializes the attributes of the printer and saves them as Preferences).

The program now redisplays the Print Dialog with the deserialized attributes shown (you can verify this by checking the Page Setup tab). When you press Print or Cancel, the program terminates.

So far so good. We've successfully deserialized the media object.

Rerun the program.

When the program attempts to deserialize the attributes, it fails as described.

At this point you can actually go to the registry and find the Preferences on this path:

My Computer\HKEY_CURRENT_USER\Software\JavaSoft\Prefs\<test program package name  | unnamed>\/<printer name here>

If you delete the entry for media, you'll note that the program can initialize and display the print dialog. That is to say, the media-printable-area entry deserializes correctly.

If you want to get back to the initial state, you can run the program with the parameter:

reinit

Or, just delete the entries from the printer's folder in the registry.

Finally, if you choose one of the standard media sizes (for which there's a static class value in the MediaPrintableArea class), there doesn't seem to be a problem. Custom page sizes cause problems too.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Printer Dialog should display, with the last settings, without an error regardless of the paper/media setting.
ACTUAL -
When you use a non-standard paper size for the media value, deserialization of the MediaPrintableArea instance fails upon initialization of the program (oddly not when it happens in the same invocation of the program as the serialization).

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.InvalidObjectException: Integer value = 0 not in valid range 0..-1for class class sun.print.Win32MediaSize
        at javax.print.attribute.EnumSyntax.readResolve(EnumSyntax.java:182)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:925)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1655)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)
        at PrtAttribDeserializer.loadAttributes(PrtAttribDeserializer.java:106)
        at PrtAttribDeserializer.<init>(PrtAttribDeserializer.java:40)
        at PrtAttribDeserializer.main(PrtAttribDeserializer.java:140)
java.io.InvalidObjectException: Integer value = 0 not in valid range 0..-1for class class sun.print.Win32MediaSize
        at javax.print.attribute.EnumSyntax.readResolve(EnumSyntax.java:182)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:925)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1655)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)
        at PrtAttribDeserializer.loadAttributes(PrtAttribDeserializer.java:106)
        at PrtAttribDeserializer.<init>(PrtAttribDeserializer.java:40)
        at PrtAttribDeserializer.main(PrtAttribDeserializer.java:140)
Exception in thread "main"


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * PrtAttribDeserializer.java
 *
 * Created on May 27, 2005, 5:14 PM
 */

import java.awt.print.*;

import java.io.*;

import javax.print.*;
import javax.print.attribute.*;

import java.util.prefs.*;

/**
 * Demonstrates the apparent bug in deserialization of some printer attribute set
 * values.
 *
 * @author  John M Craig
 */
public class PrtAttribDeserializer {
    
    private PrintService dfltPrtSrvc = null;
    
    private String       printerName = null;
    
    private PrinterJob   printerJob  = null;
    
    private HashPrintRequestAttributeSet attributeSet
        = new HashPrintRequestAttributeSet();
    
    /** Creates a new instance of PrtAttribDeserializer */
    public PrtAttribDeserializer( final boolean doReinit ) throws Exception {
        this.dfltPrtSrvc = PrintServiceLookup.lookupDefaultPrintService();
        this.printerName = dfltPrtSrvc.getName();
        this.printerJob  = PrinterJob.getPrinterJob();
        this.printerJob.setPrintService( dfltPrtSrvc );
        if ( ! doReinit ) {
            this.attributeSet = this.loadAttributes( printerName );
        } else {
            this.saveAttributes( printerName, null );
        }
    }
    
    private void saveAttributes( final String                       printerName
                               , final HashPrintRequestAttributeSet attributeSet
                               ) throws Exception {
            Preferences prefs
                = Preferences.userNodeForPackage( this.getClass() );
            Preferences prtPrefs = prefs.node( printerName );
            // if there's nothing to write, zero out everything for the printer
            // in question
            if ( attributeSet == null || attributeSet.isEmpty() ) {
                prtPrefs.clear();
                prtPrefs.flush();
                return;
            }
            // OK, got stuff to save
            ByteArrayOutputStream byteOutput = new ByteArrayOutputStream( 1024 );
        
            ObjectOutputStream objOutput = null;
            // objOutput puts a header into the byteOutput; set a mark after it
            Attribute[] attribs = attributeSet.toArray();
            for ( int i = 0; i < attribs.length; i++ ) {
                byteOutput.reset();
                // objOutput puts a header in the byteOutput buffer; recreation required
                objOutput = new ObjectOutputStream ( byteOutput );

                objOutput .writeObject( attribs[ i ] );
                objOutput .flush();
                byte[] theBytes = byteOutput.toByteArray();
                prtPrefs.putByteArray( attribs[ i ].getName()
                                     , theBytes );
                objOutput .close();
            }
            prtPrefs  .flush();
            objOutput .close();
            byteOutput.close(); // note this is a no-op; if switch implementations may be required
        
    // saveAttributes
    }
    
    private HashPrintRequestAttributeSet loadAttributes( final String printerName
                                                       ) throws Exception {
        HashPrintRequestAttributeSet attributeSet = new HashPrintRequestAttributeSet();

            Preferences prefs
                = Preferences.userNodeForPackage( this.getClass() );
            Preferences prtPrefs = prefs.node( printerName );
            byte[]               theBytes  = null;
            ByteArrayInputStream byteInput = null;
            ObjectInputStream    objInput  = null;
            String[] keys = prtPrefs.keys();
            for ( int idx = 0; idx < keys.length; idx++ ) {
                theBytes = prtPrefs.getByteArray( keys[ idx ], null );
                if ( theBytes == null || theBytes.length == 0 ) {
                    // nothing for attribute in question
                    continue;
                }
                Object attribute = null;
                try {
                    byteInput = new ByteArrayInputStream( theBytes );
                    objInput
                        = new ObjectInputStream ( byteInput );
                    attribute = objInput.readObject();
                } catch ( Exception eX ) {
                    eX.printStackTrace();
                    throw eX;
                }
                attributeSet.add( (Attribute) attribute );
                objInput .close();
                objInput  = null;
                byteInput.close(); // no-op; if modify implementation may be important
                byteInput = null;
            } // for each child node
            
        return attributeSet;
    // loadAttributes
    }

    
    public void displayDialog() throws Exception {
        if ( this.attributeSet == null ) {
            this.attributeSet = new HashPrintRequestAttributeSet();
        }
        this.printerJob.printDialog( this.attributeSet );
        this.saveAttributes( this.printerName, this.attributeSet );
    }

    
    /**
     * @param args the command line arguments
     * use 'reinit' to clear out Preferences entry
     */
    public static void main(String[] args) throws Exception {
        boolean doReinit = args.length > 0
                        && args[ 0 ].equalsIgnoreCase( "reinit" );
          
        PrtAttribDeserializer attribDeserial = new PrtAttribDeserializer( doReinit );

        System.out.println("When the dialog displays, open the Page Setup tab.");
        System.out.println("\t Change the Media to 4 x 6 & press Print." );
        System.out.println("\t Note that the dialog displays the next time with the deserialized value shown.");
        System.out.println("\t Allow the program to exit normally (press Print or Cancel); rerun to see failure.");
        System.out.println("\t To reset run with parameter: \"reinit\" " );

        attribDeserial.displayDialog();
        
        attribDeserial = new PrtAttribDeserializer( false );
        
        attribDeserial.displayDialog();

    // main
    }
    
// class PrtAttribSerializer
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I assume that if I disect the MediaPrintableArea so that I'm actually saving the x, y, h, w, and units properties, I could create a new one. Haven't had time to try that, but that's the plan.
###@###.### 2005-05-31 17:37:53 GMT

Additional customer info :
Some of the information was a bit confused. Several times, I mistakenly referred to the MediaPageSize class when I meant the Media class. It's the form/media that's the problem. But it may be a limitation of the design: there doesn't seem to be a way to create a Media instance that refers to a non-standard paper size in a way that looks like it could deserialize correctly--it's odd that it'll do it within the same JVM instance.
###@###.### 2005-07-13 18:44:30 GMT

                                    

Comments



Hardware and Software, Engineered to Work Together